From 4c188bb4a13253c12698b6edb8ad0d1d53242ae3 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 14 Jul 2013 02:31:53 +0200 Subject: [PATCH 01/39] (Makefile) Add ARM target --- Makefile.libretro | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Makefile.libretro b/Makefile.libretro index e4e210d..4b51e28 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -104,6 +104,29 @@ else ifeq ($(platform), wii) AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) PLATFORM_DEFINES := -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -DALT_RENDER STATIC_LINKING = 1 +else ifneq (,$(findstring armv,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,--no-undefined -lz + ENDIANNESS_DEFINES := -DLSB_FIRST + PLATFORM_DEFINES := -DHAVE_ZLIB + CC = gcc +ifneq (,$(findstring cortexa8,$(platform))) + PLATFORM_DEFINES += -marm -mcpu=cortex-a8 +else ifneq (,$(findstring cortexa9,$(platform))) + PLATFORM_DEFINES += -marm -mcpu=cortex-a9 +endif + PLATFORM_DEFINES += -marm +ifneq (,$(findstring neon,$(platform))) + PLATFORM_DEFINES += -mfpu=neon + HAVE_NEON = 1 +endif +ifneq (,$(findstring softfloat,$(platform))) + PLATFORM_DEFINES += -mfloat-abi=softfp +else ifneq (,$(findstring hardfloat,$(platform))) + PLATFORM_DEFINES += -mfloat-abi=hard +endif + PLATFORM_DEFINES += -DARM else TARGET := $(TARGET_NAME)_libretro.dll CC = gcc From a32165f064067a96bd052dae874d2fd5a54bb8d7 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Thu, 11 Jul 2013 23:33:11 +0200 Subject: [PATCH 02/39] [Core/Gamecube] improved progressive mode switch request on startup when component cable is detected --- gx/config.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/gx/config.c b/gx/config.c index b7b7958..cc570a3 100644 --- a/gx/config.c +++ b/gx/config.c @@ -223,27 +223,37 @@ void config_default(void) int loaded = config_load(); #ifndef HW_RVL - /* detect progressive mode enable/disable requests */ - PAD_ScanPads(); - if (PAD_ButtonsHeld(0) & PAD_BUTTON_B) + /* check if component cable was detected */ + if (VIDEO_HaveComponentCable()) { - /* swap progressive mode enable flag and play some sound to inform user */ - config.v_prog ^= 1; - ASND_Pause(0); - int voice = ASND_GetFirstUnusedVoice(); - ASND_SetVoice(voice,VOICE_MONO_16BIT,44100,0,(u8 *)intro_pcm,intro_pcm_size,200,200,NULL); - sleep (2); - ASND_Pause(1); - } + /* when component cable is detected, libogc automatically enables progressive mode */ + /* as preferred video mode but it could still be used on TV not supporting 480p/576p */ + PAD_ScanPads(); - /* switch into 480p if component cable has been detected and progressive mode is enabled */ - if (VIDEO_HaveComponentCable() && config.v_prog) - { - vmode = &TVNtsc480Prog; - VIDEO_Configure (vmode); - VIDEO_Flush(); - VIDEO_WaitVSync(); - VIDEO_WaitVSync(); + /* detect progressive mode switch requests */ + if (PAD_ButtonsHeld(0) & PAD_BUTTON_B) + { + /* swap progressive mode enable flag */ + config.v_prog ^= 1; + + /* play some sound to inform user */ + ASND_Pause(0); + int voice = ASND_GetFirstUnusedVoice(); + ASND_SetVoice(voice,VOICE_MONO_16BIT,44100,0,(u8 *)intro_pcm,intro_pcm_size,200,200,NULL); + sleep (2); + ASND_Pause(1); + } + + /* check if progressive mode should be disabled */ + if (!config.v_prog) + { + /* switch menu video mode to interlaced */ + vmode->viTVMode = (vmode->viTVMode & ~3) | VI_INTERLACE; + VIDEO_Configure (vmode); + VIDEO_Flush(); + VIDEO_WaitVSync(); + VIDEO_WaitVSync(); + } } #endif From 9d64a49781f4aab11df6b84106aa2b2575e5ed67 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Thu, 11 Jul 2013 23:34:51 +0200 Subject: [PATCH 03/39] [Gamecube/Wii] added 50hz progressive mode (576p) support for emulation --- gx/gui/menu.c | 32 +++++++++----------------------- gx/gx_video.c | 18 ++++++++++++++---- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/gx/gui/menu.c b/gx/gui/menu.c index 518d05d..4a4d63c 100644 --- a/gx/gui/menu.c +++ b/gx/gui/menu.c @@ -1548,19 +1548,12 @@ static void videomenu () config.render = (config.render + 1) % 3; if (config.render == 2) { - if (VIDEO_HaveComponentCable()) + /* progressive mode is only possible through component cable */ + if (!VIDEO_HaveComponentCable()) { - /* progressive mode (60hz only) */ - config.tv_mode = 0; - sprintf (items[1].text, "TV Mode: 60HZ"); - } - else - { - /* do nothing if component cable is not detected */ config.render = 0; } } - if (config.render == 1) sprintf (items[0].text,"Display: INTERLACED"); else if (config.render == 2) @@ -1571,21 +1564,14 @@ static void videomenu () break; case 1: /*** tv mode ***/ - if (config.render != 2) - { - config.tv_mode = (config.tv_mode + 1) % 3; - if (config.tv_mode == 0) - sprintf (items[1].text, "TV Mode: 60HZ"); - else if (config.tv_mode == 1) - sprintf (items[1].text, "TV Mode: 50HZ"); - else - sprintf (items[1].text, "TV Mode: 50/60HZ"); - reinit = 1; - } + config.tv_mode = (config.tv_mode + 1) % 3; + if (config.tv_mode == 0) + sprintf (items[1].text, "TV Mode: 60HZ"); + else if (config.tv_mode == 1) + sprintf (items[1].text, "TV Mode: 50HZ"); else - { - GUI_WaitPrompt("Error","Progressive Mode is 60hz only !\n"); - } + sprintf (items[1].text, "TV Mode: 50/60HZ"); + reinit = 1; break; case 2: /*** VSYNC ***/ diff --git a/gx/gx_video.c b/gx/gx_video.c index b0c3b70..f356b0c 100644 --- a/gx/gx_video.c +++ b/gx/gx_video.c @@ -1522,16 +1522,26 @@ void gx_video_Start(void) VIDEO_Flush(); } - /* set interlaced or progressive video mode */ + /* Enable progressive or interlaced video mode */ if (config.render == 2) { - tvmodes[2]->viTVMode = VI_TVMODE_NTSC_PROG; + /* 480p */ + tvmodes[2]->viTVMode = (tvmodes[2]->viTVMode & ~3) | VI_PROGRESSIVE; tvmodes[2]->xfbMode = VI_XFBMODE_SF; + + /* 576p */ + tvmodes[5]->viTVMode = VI_TVMODE_PAL_PROG; + tvmodes[5]->xfbMode = VI_XFBMODE_SF; } else if (config.render == 1) { - tvmodes[2]->viTVMode = tvmodes[0]->viTVMode & ~3; + /* 480i */ + tvmodes[2]->viTVMode = (tvmodes[2]->viTVMode & ~3) | VI_INTERLACE; tvmodes[2]->xfbMode = VI_XFBMODE_DF; + + /* 576i */ + tvmodes[5]->viTVMode = VI_TVMODE_PAL_INT; + tvmodes[5]->xfbMode = VI_XFBMODE_DF; } /* update horizontal border width */ @@ -1786,7 +1796,7 @@ void gx_video_Init(void) /* Get the current VIDEO mode then : - set menu video mode (480p/576p/480i/576i) - - set emulator rendering 60hz TV modes (PAL/MPAL/NTSC/EURGB60) + - set emulator rendering 60hz TV modes (MPAL/NTSC/EURGB60) */ vmode = VIDEO_GetPreferredMode(NULL); From 0a3e3487fdd645c685d0184375f76008b6e81cf3 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 14 Jul 2013 02:37:56 +0200 Subject: [PATCH 04/39] (Libretro) Bump up version number - we might want to make this a global define with only the version number --- libretro/libretro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretro/libretro.c b/libretro/libretro.c index 4cfb8fb..6cc3723 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -463,7 +463,7 @@ static struct retro_system_av_info g_av_info; void retro_get_system_info(struct retro_system_info *info) { info->library_name = "Genesis Plus GX"; - info->library_version = "v1.7.3"; + info->library_version = "v1.7.4"; info->valid_extensions = "md|smd|bin|cue|gen|iso|sms|gg|sg"; info->block_extract = false; info->need_fullpath = true; From 93d2db88b7c48a15c4fc4ec5363b0972b7d9146c Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 14 Jul 2013 17:05:44 +0200 Subject: [PATCH 05/39] [Core/CDD] added compiler define option to disallow opening multiple .ogg files at the same time for platforms with limited RAM (fixes memory crash on Gamecube when using too many .ogg files) --- Makefile.gc | 2 +- core/cd_hw/cdd.c | 181 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 155 insertions(+), 28 deletions(-) diff --git a/Makefile.gc b/Makefile.gc index 7305178..8eb625f 100644 --- a/Makefile.gc +++ b/Makefile.gc @@ -27,7 +27,7 @@ INCLUDES := core core/m68k core/z80 core/sound core/tremor core/ntsc core/input_ # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -O3 -fomit-frame-pointer --param large-function-growth=800 --param inline-unit-growth=200 -Wall -Winline -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_LIBTREMOR -DUSE_16BPP_RENDERING -DALT_RENDERER +CFLAGS = -O3 -fomit-frame-pointer --param large-function-growth=800 --param inline-unit-growth=200 -Wall -Winline -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_LIBTREMOR -DDISABLE_MANY_OGG_OPEN_FILES -DUSE_16BPP_RENDERING -DALT_RENDERER CXXFLAGS = $(CFLAGS) LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map diff --git a/core/cd_hw/cdd.c b/core/cd_hw/cdd.c index cee5e66..548c5e4 100644 --- a/core/cd_hw/cdd.c +++ b/core/cd_hw/cdd.c @@ -152,6 +152,26 @@ static const char extensions[SUPPORTED_EXT][16] = static blip_t* blip[2]; + +#ifdef USE_LIBTREMOR +#ifdef DISABLE_MANY_OGG_OPEN_FILES +static void ogg_free(int i) +{ + /* clear OGG file descriptor to prevent file from being closed */ + cdd.toc.tracks[i].vf.datasource = NULL; + + /* close VORBIS file structure */ + ov_clear(&cdd.toc.tracks[i].vf); + + /* indicates that the track is a seekable VORBIS file */ + cdd.toc.tracks[i].vf.seekable = 1; + + /* reset file reading position */ + fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET); +} +#endif +#endif + void cdd_init(blip_t* left, blip_t* right) { /* CD-DA is running by default at 44100 Hz */ @@ -206,6 +226,16 @@ int cdd_context_load(uint8 *state) int lba; int bufferptr = 0; +#ifdef USE_LIBTREMOR +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* close previous track VORBIS file structure to save memory */ + if (cdd.toc.tracks[cdd.index].vf.datasource) + { + ogg_free(cdd.index); + } +#endif +#endif + load_param(&cdd.cycles, sizeof(cdd.cycles)); load_param(&cdd.latency, sizeof(cdd.latency)); load_param(&cdd.index, sizeof(cdd.index)); @@ -231,14 +261,19 @@ int cdd_context_load(uint8 *state) } } #ifdef USE_LIBTREMOR - else if (cdd.toc.tracks[cdd.index].vf.datasource) + else if (cdd.toc.tracks[cdd.index].vf.seekable) { +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* VORBIS file need to be opened first */ + ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0); +#endif + /* VORBIS AUDIO track */ ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset); } -#endif +#endif else if (cdd.toc.tracks[cdd.index].fd) { - /* AUDIO track */ + /* PCM AUDIO track */ fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET); } @@ -564,7 +599,12 @@ int cdd_load(char *filename, char *header) cdd.toc.tracks[cdd.toc.last].offset = 0; break; } - } + +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* close VORBIS file structure to save memory */ + ogg_free(cdd.toc.last); +#endif + } else #endif { @@ -718,6 +758,11 @@ int cdd_load(char *filename, char *header) cdd.toc.tracks[cdd.toc.last].end -= 150; } +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* close VORBIS file structure to save memory */ + ogg_free(cdd.toc.last); +#endif + /* update TOC end */ cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end; @@ -854,23 +899,21 @@ void cdd_unload(void) #ifdef USE_LIBTREMOR if (cdd.toc.tracks[i].vf.datasource) { - /* close VORBIS file */ + /* close VORBIS file (if still opened) */ ov_clear(&cdd.toc.tracks[i].vf); } else #endif + if (cdd.toc.tracks[i].fd) { - if (cdd.toc.tracks[i].fd) - { - /* close file */ - fclose(cdd.toc.tracks[i].fd); + /* close file */ + fclose(cdd.toc.tracks[i].fd); - /* detect single file images */ - if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd) - { - /* exit loop */ - i = cdd.toc.last; - } + /* detect single file images */ + if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd) + { + /* exit loop */ + i = cdd.toc.last; } } } @@ -1130,6 +1173,15 @@ void cdd_update(void) /* check end of current track */ if (cdd.lba >= cdd.toc.tracks[cdd.index].end) { +#ifdef USE_LIBTREMOR +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* close previous track VORBIS file structure to save memory */ + if (cdd.toc.tracks[cdd.index].vf.datasource) + { + ogg_free(cdd.index); + } +#endif +#endif /* play next track */ cdd.index++; @@ -1138,8 +1190,12 @@ void cdd_update(void) /* seek to next audio track start */ #ifdef USE_LIBTREMOR - if (cdd.toc.tracks[cdd.index].vf.datasource) + if (cdd.toc.tracks[cdd.index].vf.seekable) { +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* VORBIS file need to be opened first */ + ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0); +#endif ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, -cdd.toc.tracks[cdd.index].offset); } else @@ -1160,6 +1216,15 @@ void cdd_update(void) /* check current track limits */ if (cdd.lba >= cdd.toc.tracks[cdd.index].end) { +#ifdef USE_LIBTREMOR +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* close previous track VORBIS file structure to save memory */ + if (cdd.toc.tracks[cdd.index].vf.datasource) + { + ogg_free(cdd.index); + } +#endif +#endif /* next track */ cdd.index++; @@ -1174,6 +1239,16 @@ void cdd_update(void) } else if (cdd.lba < cdd.toc.tracks[cdd.index].start) { +#ifdef USE_LIBTREMOR +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* close previous track VORBIS file structure to save memory */ + if (cdd.toc.tracks[cdd.index].vf.datasource) + { + ogg_free(cdd.index); + } +#endif +#endif + /* previous track */ cdd.index--; @@ -1209,15 +1284,23 @@ void cdd_update(void) fseek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET); } #ifdef USE_LIBTREMOR - else if (cdd.toc.tracks[cdd.index].vf.datasource) + else if (cdd.toc.tracks[cdd.index].vf.seekable) { +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* check if a new track is being played */ + if (!cdd.toc.tracks[cdd.index].vf.datasource) + { + /* VORBIS file need to be opened first */ + ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0); + } +#endif /* VORBIS AUDIO track */ ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset); } #endif else if (cdd.toc.tracks[cdd.index].fd) { - /* AUDIO track */ + /* PCM AUDIO track */ fseek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET); } } @@ -1389,11 +1472,33 @@ void cdd_process(void) /* update current LBA */ cdd.lba = lba; - /* update current track index */ + /* get track index */ while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++; + +#ifdef USE_LIBTREMOR +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* check if track index has changed */ + if (index != cdd.index) + { + /* close previous track VORBIS file structure to save memory */ + if (cdd.toc.tracks[cdd.index].vf.datasource) + { + ogg_free(cdd.index); + } + + /* open current track VORBIS file */ + if (cdd.toc.tracks[index].vf.seekable) + { + ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0); + } + } +#endif +#endif + + /* update current track index */ cdd.index = index; - /* stay within track limits */ + /* stay within track limits when seeking files */ if (lba < cdd.toc.tracks[index].start) { lba = cdd.toc.tracks[index].start; @@ -1406,15 +1511,15 @@ void cdd_process(void) fseek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET); } #ifdef USE_LIBTREMOR - else if (cdd.toc.tracks[index].vf.datasource) + else if (cdd.toc.tracks[index].vf.seekable) { /* VORBIS AUDIO track */ - ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[cdd.index].offset); + ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset); } #endif else if (cdd.toc.tracks[index].fd) { - /* AUDIO track */ + /* PCM AUDIO track */ fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET); } @@ -1459,8 +1564,30 @@ void cdd_process(void) /* update current LBA */ cdd.lba = lba; - /* update current track index */ + /* get current track index */ while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++; + +#ifdef USE_LIBTREMOR +#ifdef DISABLE_MANY_OGG_OPEN_FILES + /* check if track index has changed */ + if (index != cdd.index) + { + /* close previous track VORBIS file structure to save memory */ + if (cdd.toc.tracks[cdd.index].vf.datasource) + { + ogg_free(cdd.index); + } + + /* open current track VORBIS file */ + if (cdd.toc.tracks[index].vf.seekable) + { + ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0); + } + } +#endif +#endif + + /* update current track index */ cdd.index = index; /* stay within track limits */ @@ -1476,15 +1603,15 @@ void cdd_process(void) fseek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET); } #ifdef USE_LIBTREMOR - else if (cdd.toc.tracks[index].vf.datasource) + else if (cdd.toc.tracks[index].vf.seekable) { /* VORBIS AUDIO track */ - ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[cdd.index].offset); + ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset); } #endif else if (cdd.toc.tracks[index].fd) { - /* AUDIO track */ + /* PCM AUDIO track */ fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET); } From d973d7d39e1ee884e9476fbb27cdbe164e020437 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 14 Jul 2013 19:55:37 +0200 Subject: [PATCH 06/39] [Core/VDP] modified Master System color palette to use full brightness range (verified against real hardware) --- core/vdp_render.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/vdp_render.c b/core/vdp_render.c index d9c9570..2bf951f 100644 --- a/core/vdp_render.c +++ b/core/vdp_render.c @@ -965,10 +965,11 @@ static void palette_init(void) /* normal : xxx0 (0-14) */ /* shadow : 0xxx (0-7) */ /* highlight: 1xxx - 1 (7-14) */ - /* mode4 : xx00 ? (0-12) */ - /* GG mode : xxxx (0-16) */ + /* mode4 : xxxx(*) (0-15) */ + /* GG mode : xxxx (0-15) */ /* */ /* with x = original CRAM value (2, 3 or 4-bit) */ + /* (*) 2-bit CRAM value is expanded to 4-bit */ /************************************************/ /* Initialize Mode 5 pixel color look-up tables */ @@ -993,8 +994,8 @@ static void palette_init(void) g = (i >> 2) & 3; b = (i >> 4) & 3; - /* Convert to output pixel format (expand to 4-bit for brighter colors ?) */ - pixel_lut_m4[i] = MAKE_PIXEL(r << 2,g << 2,b<< 2); + /* Expand to full range & convert to output pixel format */ + pixel_lut_m4[i] = MAKE_PIXEL((r << 2) | r, (g << 2) | g, (b << 2) | b); } } From d3fbc1af606794d71096cde431fba2dd640ec6c5 Mon Sep 17 00:00:00 2001 From: ToadKing Date: Sun, 15 Sep 2013 17:10:42 -0400 Subject: [PATCH 07/39] emscripten support --- Makefile.libretro | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile.libretro b/Makefile.libretro index 4b51e28..410a45e 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -5,6 +5,10 @@ FRONTEND_SUPPORTS_RGB565 = 1 GENPLUS_SRC_DIR := core LIBRETRO_DIR := libretro +ifneq ($(EMSCRIPTEN),) + platform = emscripten +endif + ifeq ($(platform),) platform = unix ifeq ($(shell uname -a),) @@ -127,6 +131,9 @@ else ifneq (,$(findstring hardfloat,$(platform))) PLATFORM_DEFINES += -mfloat-abi=hard endif PLATFORM_DEFINES += -DARM +else ifeq ($(platform), emscripten) + TARGET := $(TARGET_NAME)_libretro_emscripten.bc + ENDIANNESS_DEFINES := -DLSB_FIRST else TARGET := $(TARGET_NAME)_libretro.dll CC = gcc @@ -138,13 +145,13 @@ endif ifeq ($(DEBUG), 1) CFLAGS += -O0 -g -else -ifeq ($(platform),qnx) +else ifeq ($(platform),qnx) CFLAGS += -Os -DNDEBUG +else ifeq ($(platform), emscripten) + CFLAGS += -O2 -DNDEBUG else CFLAGS += -O3 -DNDEBUG endif -endif LIBRETRO_SRC := $(GENPLUS_SRC_DIR)/genesis.c \ $(GENPLUS_SRC_DIR)/vdp_ctrl.c \ From b55896a2a84aa6ba858657dca5671e10de5144df Mon Sep 17 00:00:00 2001 From: ToadKing Date: Sat, 12 Oct 2013 18:33:21 -0400 Subject: [PATCH 08/39] fix snprintf --- libretro/libretro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretro/libretro.c b/libretro/libretro.c index 6cc3723..daee76d 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -715,7 +715,7 @@ bool retro_load_game(const struct retro_game_info *info) fprintf(stderr, "Sega CD JP BRAM is located at: %s\n", CD_BRAM_JP); fprintf(stderr, "Sega CD RAM CART is located at: %s\n", CART_BRAM); - snprintf(DEFAULT_PATH, sizeof(DEFAULT_PATH), g_rom_dir); + snprintf(DEFAULT_PATH, sizeof(DEFAULT_PATH), "%s", g_rom_dir); config_default(); init_bitmap(); From e316c8fff3f875ff95297449682830d94557bf67 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Fri, 2 Aug 2013 22:34:34 +0200 Subject: [PATCH 09/39] [Gamecube/Wii] fixed low-pass filter menu setting --- gx/gui/menu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gx/gui/menu.c b/gx/gui/menu.c index 4a4d63c..42a68cd 100644 --- a/gx/gui/menu.c +++ b/gx/gui/menu.c @@ -844,7 +844,7 @@ static void soundmenu () } else if (config.filter == 1) { - int lp_range = (config.lp_range * 100 + 0xffff) / 0x10000; + int16 lp_range = (config.lp_range * 100 + 0xffff) / 0x10000; sprintf (items[7].text, "Filtering: LOW-PASS"); sprintf (items[8].text, "Low-Pass Rate: %d %%", lp_range); strcpy (items[9].comment, "Adjust Low Pass filter"); @@ -987,7 +987,7 @@ static void soundmenu () { if (config.filter == 1) { - int lp_range = (config.lp_range * 100 + 0xffff) / 0x10000; + int16 lp_range = (config.lp_range * 100 + 0xffff) / 0x10000; GUI_OptionBox(m,0,"Low-Pass Rate",(void *)&lp_range,1,0,100,1); sprintf (items[8].text, "Low-Pass Rate: %d %%", lp_range); config.lp_range = (lp_range * 0x10000) / 100; From ad9291cc7bd6ddf40dbe5702a2e3eb7108eb50aa Mon Sep 17 00:00:00 2001 From: ekeeke Date: Sun, 8 Sep 2013 17:17:36 +0200 Subject: [PATCH 10/39] Create README.md --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..984d1f7 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +About +--------- + +Genesis Plus GX is an open-source & portable Sega Mega Drive / Genesis emulator,now also emulating SG-1000, Master System, Game Gear and Sega/Mega CD. + +The source code is based on Genesis Plus 1.3, originally developped by Charles MacDonald (http://cgfm2.emuviews.com). +It has been heavily modified, with respect to initial goals and design, in order to improve accuracy of emulation, implementing new features and adding support for extra peripherals, cartridge & system hardwares. + +The result is that Genesis Plus GX is now more a continuation of the original project than a simple port, providing very accurate emulation and 100% compatibility with Genesis / Mega Drive, Sega / Mega CD, Master System, Game Gear & SG-1000 software (including all unlicensed or pirate known dumps), also emulating backwards compatibility modes when available. + +Multi-platform sourcecode is available through SVN and GIT so that other Genesis Plus ports can take advantage of it. The sourcecode is released under a specific non-commercial license, see LICENSE.txt for more informations. + + +Usage +--------- + +(*) standalone Gamecube / Wii port: + +see http://code.google.com/p/genplus-gx/wiki/GettingStarted + + +(*) libretro / Retroarch (Multi Platform) port: + +see http://forum.themaister.net/ + + +Features +------------- + +see http://code.google.com/p/genplus-gx/wiki/Features + + +Credits +---------- + +see http://code.google.com/p/genplus-gx/wiki/Credits + From 574a5891a3612754c9e834bc40b9e7543ec8f122 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 8 Sep 2013 17:27:42 +0200 Subject: [PATCH 11/39] added HISTORY.txt and LICENSE.txt --- HISTORY.txt | 1023 +++++++++++++++++++++++++++++++++++++++ LICENSE.txt | 621 ++++++++++++++++++++++++ README.md => README.txt | 0 3 files changed, 1644 insertions(+) create mode 100644 HISTORY.txt create mode 100644 LICENSE.txt rename README.md => README.txt (100%) diff --git a/HISTORY.txt b/HISTORY.txt new file mode 100644 index 0000000..8e63db4 --- /dev/null +++ b/HISTORY.txt @@ -0,0 +1,1023 @@ +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.4 (21/06/2013) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* fixed access to read-only registers on Main-CPU side ("Batman Returns" platform level freeze) +* fixed & improved emulation of PRG-RAM write protection register ("Lunar Eternal Blue" japanese version freeze) +* improved SUB & MAIN-CPU synchronization ("Dracula Unleashed" freeze when using US Model 2 BIOS) +* improved CPU polling detection +* improved CDD emulation & added CD drive access time for SEEK command ("Panic!/Switch" intro missing scene) +* added missing reinitialization of MAIN-CPU PRG-RAM bank on reset +* added .OGG audio tracks support through LIBTREMOR + +[Core/Sound] +--------------- +* fixed YM2612 configurable DAC depth emulation +* improved Low-Pass filter +* added optional "MONO" output mode + +[Core/VDP] +--------------- +* fixed FIFO access timings when using invalid write code value ("Clue" menu) +* fixed DMA Copy with undocumented code value ("Fatal Labyrinth" end sequence) +* minor code fixes & optimizations + +[Core/CPU] +--------------- +* optimized 68k stack read/write functions +* fixed broken 68k address error emulation +* fixed 68k interrupt behavior (prevents interrupts from being executed multiple time when 68k is halted) +* fixed Z80 registers initial state, added proper initialization when using PBC (verified on real hardware by Charles McDonald) + +[Core/MD] +--------------- +* fixed SRAM incompatibilities between BIG ENDIAN & LITTLE ENDIAN platforms (note: this breaks old .srm files with LITTLE ENDIAN platform ports) +* added support for a few recently dumped unlicensed games +* added auto-detection of byte-swapped ROM files + +[Gamecube/Wii] +--------------- +* fixed CD Leds positioning when using NTSC filter +* improved on-screen CD Leds (thanks to Iceknight) +* various code fixes & improvements + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.3 (26/11/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Gamecube/Wii] +--------------- +* fixed broken input system initialization + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.2 (24/11/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* added default TOC for Shadow of the Beast II (prevent hangs when audio tracks are missing) +* fixed CD-DA fader muting +* fixed PCM channels panning on reset +* fixed backup RAM file management when using disc swap with Mode 1 cartridge +* incremented CD drive read latency: fixes Space Adventure Cobra (freeze when opening coffin at 2nd morgue scene) +* improved CDD emulation accuracy: fixes Snatcher (freeze at the end of Act 2) & various CD player bugs +* improved MAIN-SUB memory map mirroring in SCD mode (verified on real hardware by Charles McDonald) +* implemented cycle-accurate "stopwatch" register emulation + +[Core/Sound] +--------------- +* fixed broken PSG noise frequency +* fixed incorrect Game Gear PSG stereo emulation +* implemented cycle-accurate Game Gear PSG stereo + +[Core/VDP] +--------------- +* fixed broken VDP DMA from SVP ROM latency (graphic errors in Virtua Racing) + +[Core/MD] +--------------- +* added Super Mario World 64 (unlicensed) cartridge hardware emulation + +[Core/Input] +--------------- +* added automatic detection for CD games with Justifier/Menacer support +* improved Justifier/Menacer emulation + +[Gamecube/Wii] +--------------- +* fixed screen rendering when borders are disabled +* added configurable on-screen CD leds + +[Wii] +--------------- +* DVD light now indicates when virtual CD tray is open +* fixed automatic input settings detection +* improved lightgun crosshair positionning + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.1 (13/10/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* added support for CUE files +* added CD-DA tracks emulation (needs CUE+BIN or ISO+WAV images) +* added CD fader emulation +* added CDD "Fast FW" & "Fast RW" commands emulation +* improved CDD TOC emulation (random freezes in Sonic CD, Switch/Panic, Final Fight CD and probably many others) +* improved PCM chip synchronization with SUB-CPU (missing speeches in Willy Beamish) +* fixed PCM chip emulation (random hangs in Snatcher, missing sound effects in Switch/Panic, Final Fight CD, Wonderdog...) +* fixed Word-RAM memory mode on soft-reset (missing logo gfx effects) +* fixed SUB-CPU access to unused areas when using PC-relative instructions (Final Fight CD first boss random crash) +* fixed CPU idle loop detection on memory mode register access (Pugsy CD first boss slowdown) +* fixed Mode 1 emulation (cartridge boot mode) + +[Core/Sound] +--------------- +* replaced FIR resampler by Blip Buffer for FM resampling +* modified SN76489 core for use of Blip Buffer +* improved PSG & FM chips synchronization using Blip Buffer +* added Game Gear PSG stereo support +* fixed SG-1000 specific PSG noise +* fixed YM2612 LFO AM waveform (California Games surfing event) +* fixed YM2612 phase precision +* minor optimizations to YM2612 core + +[Core/Game Gear] +--------------- +* added support for CJ Elephant Fugitive (recently released by SMS Power) +* added Game Gear extended screen option + +[Core/Genesis] +--------------- +* added support for a few recently dumped (but unreleased) games + +[Core/General] +--------------- +* improved ROM & CD image file loading +* various code cleanup + +[Gamecube/Wii] +--------------- +* added automatic disc swap feature +* removed automatic frameskipping (no use) +* improved general audio/video sync +* various code cleanup & bugfixes + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.0 (01/07/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* added Mega CD / Sega CD hardware emulation (incl. Sub 68K, CDD, CDC, PCM, GFX rotation/scaling, etc) +* added .ISO & .BIN CD image file support +* added 512K backup cartridge RAM support +* added savestate support for CD games + +NOTES: +~~~~~~ +* to play CD games, original BIOS ROM files are required in /genplus/bios/ directory: unzip & rename them to bios_CD_U.bin, bios_CD_E.bin, bios_CD_J.bin +* CD audio tracks (CD-DA) are not supported (yet) + +[Core/CPU] +--------------- +* modified 68k core for Mega CD / Sega CD support +* optimized 68k core using prebuild const tables + +[Core/VDP] +--------------- +* improved DMA accuracy +* improved accuracy of nametables register & VSRAM writes during HBLANK: fixes "The Adventures of Batman & Robin" (graphical issues during 2nd Boss fight). +* added support for 8-bit VRAM writes with undocumented code value (verified on real hardware by Nemesis) + +[Core/Sound] +--------------- +* improved synchronization between SN76489 & YM2162 cores. +* improved accuracy of SN76489 core timings. + +[Core/MD] +--------------- +* added support for some recently dumped unlicensed games. +* improved emulation of 32k bankswitch hardware used by a few unlicensed games. +* fixed behavior of Z80 banked reads from 68k RAM (verified on real hardware). +* fixed support for 128K Pro Action Replay ROM. + +[Core/MS] +--------------- +* added support for all recent korean ROM dumps by SMS Power. +* added emulation of korean multi-game mapper (4-Pak All Action) +* added pseudo-random RAM pattern initialization on Mark-III and Japanese Master System (fixes "Alibaba and 40 Thieves" & "Block Hole") +* added port $3E emulation & internal BOOTROM support (Master System & Game Gear only). + +[Core/General] +--------------- +* added an option to set VDP mode (PAL/NTSC) independently from console region. +* added an option to select original system master clock frequency (PAL/NTSC/AUTO), emulation will run at selected frequency when VSYNC is disabled. +* fixed 68k context loading/saving (Sol Deace). +* fixed C89 incompatibilities for better portability. +* removed use of "long int" type for portability on 64-bit platforms. +* moved savestate zlib compression out of emulation core (for ports that don't use it). +* various optimizations. + +[Gamecube/Wii] +--------------- +* removed ROM load device selection from Load Menu: default ROM device must now be configured in menu settings. +* added specific load buttons, browsers & saved paths for each systems, this also fixes slowdowns caused by screenshot loading when browsing from slow devices. +* added support for left/right buttons as page up/down keys in ROM browsers +* added right analog stick as default "return to menu" key for Gamecube controllers +* added alternate remappable menu key combo for Gamecube controllers +* added an option to disable VSYNC (emulator is synced with audio hardware instead of video). +* added an option to boot system from "BIOS", with or without cartridge. +* added Master System & Game Gear "BIOS" support (files should be named bios_U.sms, bios_J.sms, bios_E.sms & bios.gg and copied to /genplus/bios directory). +* replaced "Hard Reset" button by a Soft Reset for systems having a Reset button (Mega Drive / Genesis & Master System) +* State & SRAM files are now only compressed when saving to Gamecube Memory Cards +* various fixes & cleanup. +* compiled with devkitPPC r26 & libogc 1.8.11. + +[Gamecube] +---------- +* improved progressive mode support when component cable is detected (hold B during startup to switch menu video mode configuration) + + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.6.0 (07/08/2011) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/Sound] +--------------- +* added YM2413 emulation in Master System compatibility mode. +* fixed SN76489 noise boost initialization. +* minor YM2612 core optimizations. + +[Core/VDP] +--------------- +* added accurate emulation of SG-1000, Master System (315-5124, 315-5246) & Game Gear VDP. +* added support for all TMS9918 rendering modes. +* improved Mega Drive VDP timings accuracy in Master System Compatibility mode. +* fixed color palette initialization. +* fixed shifted sprites rendering in Mode 4. +* modified pixel rendering support (pixel depth is now forced at compilation time). + +[Core/CPU] +--------------- +* optimized 68k core (rewrote 68k interrupt handling, removed multiple CPU types support & unused code) for 5~8% speed improvment + +[Core/IO] +--------------- +* added accurate emulation of Master System (315-5216, 315-5237, 315-5297) & Game Gear I/O controllers. +* added Terebi Oekaki tablet emulation. +* improved Mouse emulation (fixes mouse support in Cannon Fodder). +* improved Justifier emulation (fixes gun support in Lethal Enforcers 2). +* improved 6-Buttons control pad emulation (fixes Duke Nukem 3D) +* modified lightgun emulation to use common key inputs for all devices. +* 2-buttons controller is now picked by default for Master System games. + +[Core/MD] +--------------- +* added copy-protection hardware emulation for some new dumped games (Tiny Toon Adventures 3, Mighty Morphin Power Rangers & The Battle of Red Cliffs). +* added Game Toshokan in EEPROM database (verified on real cartridge). +* fixed Micro Machines 2 - Turbo Tournament EEPROM size (verified on real cartridge). +* modified SRAM banswitch hardware emulation to be more compatible with some hacks. + +[Core/MS] +--------------- +* added Cyborg Z to Korean mapper database. +* +[Core/GG] +--------------- +* added 93C46 EEPROM emulation (Majors Pro Baseball, World Series Baseball & World Series Baseball 95). + +[Core/General] +--------------- +* added support for .mdx ROM format. +* added Game Gear & SG-1000 ROM support. +* added accurate emulation of SG-1000, Master System (I, II) & Game Gear hardware models for 100% compatibility. +* updated to new Genesis Plus license (see http://cgfm2.emuviews.com/) +* various code cleanup. + +[Gamecube/Wii] +--------------- +* IMPORTANT: cheats, screenshots & save files are now stored in console-specific directories (ex: /snaps/md, /cheats/ms, /saves/gg, ...) +* added 8-bit Action Replay & Game Genie codes support (for Master System & Game Gear games). +* improved audio/video synchronization for PAL games in 50Hz TV modes (now use VSYNC like NTSC games in 60hz modes). +* improved gun cursor positioning accuracy. +* improved horizontal scaling & screenshots rendering in H32 mode. +* fixed a bug with ROM file extension handling that would affect cheats, snapshots, sram & savestate files. +* removed ARAM/injected ROM support (unused). +* removed WPAD_ and PAD_ update from VSYNC callback. +* increased GCC inlining limits for some speed improvment. +* compiled with devkitPPC r24 & libogc 1.8.7. + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.5.0 (31/03/2011) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/VDP] +--------------- +* added support for Master System compatibility mode (Z80 ports access mode), incl. Mode 5 rendering. +* added Mode 4 rendering for both Genesis & Master System modes. +* added alternate BG planes rendering functions (should be faster on PPC architectures). + +[Core/IO] +--------------- +* added support for Master System compatibility mode (Z80 ports access mode). +* added Master System peripherals emulation (Control Pad, Paddle, Sports Pad & Light Phaser). +* added XE-1AP (analog controller) emulation. +* added Activator emulation. + +[Core/Extra] +--------------- +* added support for all known Master System cartridge mappers. +* added copy-protection hardware emulation for a few MD unlicensed games: fixes 777 Casino (crash when talking to bunny girls). +(NB: most of those unlicensed games seem to have been already patched by ROM dumpers, main purpose is documenting them) +* added support for Top Shooter arcade board controller. (A=Shoot, B=Bet, C/RIGHT=Coins, START=Start, hold UP on startup to enter service mode) +* improved King of Fighters 98 mapper emulation (registers address decoding is now 100% accurate) +* fixed Game Genie when several codes affect same ROM address. +* fixed EEPROM types for Brian Lara Cricket & NBA Jam TE (verified on real cartridges) + +[Core/General] +--------------- +* added Master System compatibility mode emulation (automatically enabled when loading ROM file with .sms extension). +* improved savestate stability & compatibility (support for old 1.4.x savestates is preserved) +* various code cleanup & comments. + +[Gamecube/Wii] +--------------- +* fixed cheat codes handling when several codes affect same ROM address. +* improved input controller detection on menu exit. +* improved key remapping dialog box to match emulated device +* changed Menu key for Gamecube controller to allow MODE button mapping +* fixed DVD not being unmounted on swap (memory leak) + +[Wii only] +--------------- +* added USB mouse support for Sega Mouse emulation +* compiled with latest libogc: improves USB compatibility & fixes stability issues with Wiimotes. + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.4.1 (04/12/2010) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/VDP] +--------------- +* improved VBLANK flag accuracy, as observed on real hardware. +* improved DMA operations accuracy, writes are now performed on a scanline basis: fixes Gaiares (flickering title screen). +* improved DMA Fill timing accuracy. +* fixed DMA with bad code values: fixes Williams Arcade Classics (corrupted gfx after soft reset). +* fixed horizontal resolution changes during HBLANK: fixes Bugs Bunny in Double Trouble (2nd stage). +* fixed Vertical Counter in interlace mode 1, as observed on real hardware. +* fixed horizontal border width, as observed on real hardware. +* various code improvments & optimizations. + +[Core/Extra] +--------------- +* improved savestate format: added DMA, SVP, cartridge mapping & internal registers state informations +* improved unlicensed ROM mappers emulation +* added Chinese Fighters III mapper support +* added Top Fighter mapper support +* fixed Barver Battle Saga mapper support +* fixed cartridge hardware soft-reset (Game Genie, SVP, ...) +* fixed Game Genie registers byte reads + +[Gamecube/Wii] +--------------- +* added message box when inputs config uses disconnected controllers. +* added message box when settings are reseted to default on startup. +* fixed default inputs configuration. +* fixed memory leak in Cheat Menu causing spurious resets. +* added an option to enable/disable automatic cheat activation +* increased max number of cheat codes +* optimized cheat codes requiring RAM patching. +* improved default horizontal scaling to better match output from a real Mega Drive + +[Gamecube specific] +--------------- +* fixed inverted keys in cheat menu. +* fixed audio input frequency, now use exact audio hardware samplerate, as measured on my Game Cube (~48044 Hz), + (NB: Wii samplerate has been verified to be closer to 48000 Hz) + +[Wii specific] +--------------- +* added the possibility for any wiimotes to be used as input device, regardless of the connected expansion controller. +* fixed USB drive not being detected when application is loaded from USB (HBC), thanks to Tantric for the tips. + + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.4.0 (01/11/2010) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/Sound] +--------------- +* completely rewrote sound processing/mixing: sound chips are now clocked with exact output framerate +to ensure 100% smooth video & audio playback, with no lag or skipping, while rendering an accurate number +of samples per frame and keeping PSG & FM chips in sync. +* improved PSG & FM chips synchronization with CPU execution (fixed point precision). +* improved YM2612 core general accuracy (SSG-EG, CSM mode,...) (based upon Nemesis recent tests on real hardware) +* improved YM2612 LFO emulation accuracy: fixes "Spider-Man & Venom : Separation Anxiety" (intro) +* fixed YM2612 bug with Timer B: fixes "Langrisser Hikari II"/"Der Langrisser II" (Sega logo) +* fixed YM2612 context saving/loading. +* fixed YM2612 state on reset. +* removed outdated & less accurate Gens YM2612 core +* added configurable YM2612 DAC resolution emulation. +* added configurable & faster FIR resampler (thanks to Blargg & AamirM), removed libsamplerate support. +* added configurable Low-Pass filtering +* added configurable 3-Band Equalizer (thanks to Neil C). +* added an option to boost SN76489 Noise Channel. +* adjusted SN76489 cut-off frequency. +* implemented Blargg's blip buffer in SN76489 core (all channels are now lineary interpolated) + +[Core/VDP] +--------------- +* added support for CRAM writes during horizontal blanking (Striker, Zero the Kamikaze Squirrel,...) +* added support for 2-Cell vertical scrolling in Interlaced 2 mode +* added support for some undocumented mode register bits +* added proper emulation of HV Counter latch: fixes Sunset Riders intro +* added pixel-accurate emulation of mid-line display on/off (Nigel Mansell World Championship PAL, Ren & Stimpy's Invention PAL,...) +* improved 2-cell vscroll emulation accuracy, as verified on real hardware (Gynoug, Cutie Suzuki no Ringside Angel, Formula One, Kawasaki Superbike Challenge) +* improved FIFO timings accuracy: fixes Sol Deace intro +* improved sprite masking accuracy (thanks to Nemesis for his test program) +* improved sprites processing accuracy: fixes (un)masked sprites in Mickey Mania (3D level), Sonic 2 (VS mode). +* improved HBLANK flag timing accuracy: fixes Mega Turrican (Sky level) +* improved horizontal blanking & HINT/VINT occurence timing accuracy, as measured on real hardware. +* improved HCounter accuracy in 40-cell mode, as measured on real hardware. +* improved color accuracy in VDP highlight mode to match results observed on real hardware + +[Core/CPU] +--------------- +* updated Z80 core to last version (fixes interrupt Mode 0 timing and some BIT instructions). +* fixed some Z80 instructions timing. +* fixed state of Z80 registers on reset (sound issues with Defender & Defender 2 in Williams Arcade Classics) +* improved Z80 interrupt accuracy +* improved 68k accuracy (initial Reset timing + auto-vectored interrupts handling). +* improved 68k timing accuracy for DIVU/DVIS (thanks to Jorge Cwik) & MULU/MULS instructions. +* implemented 68k undocumented flags behavior for DIVU/DIVS instructions (Bloodshot / Battle Frenzy) +* improved Z80 & 68k cpu execution/synchronization accuracy by using Master Clock as common reference (now run exactly 3420 M-Cycles per line). +* modified Z80 & 68k cores to directly use external cycle count instead of intermediate counters. + +[Core/Extra] +--------------- +* added Game Genie hardware emulation. +* added Action Replay & Pro Action Replay hardware emulation (only preliminary Pro Action Replay 2 support). +* added Sonic & Knuckles "Lock-On" support. +* added Cartridge "Hot Swap" feature. +* added missing EEPROM support in more games. +* added VDP lock-out emulation (TMSS). +* improved emulation of copy-protection hardware found in some unlicensed cartridges (Mulan, Pocket Monsters II). +* fixed Realtec mapper emulation: fixes missing sound in Balloon Boy / Funny World. +* fixed lightgun auto-detection: fixes default cursor position in Lethal Enforcers II. +* enabled simultaneous use of multitap & J-CART (Super Skidmarks 6-player mode) +* lots of code cleanup, bugfixes & optimization. + + +[Gamecube/Wii] +--------------- +* implemented custom FONT engine (uses internal IPL font & GX hardware rendering). +* implemented custom GUI engine (uses GX hardware rendering & multithreading) +* implemented advanced menu interface (IR pointing, game snapshots, cheats & saves manager, visual & sound effects, BGM support, etc). +* improved audio/video synchronization to ensure 100% smooth video & audio playback. +* improved soft-reset button support, now works more like real Mega Drive / Genesis (model 1) reset button. +* improved lightgun cursors layout. +* added automatic ROM loading feature (last played game launches immediately when starting the emulator) +* added PAR codes and .pat files support +* fixed lot of stability issues and potential memory leaks. + +[Wii specific] +--------------- +* added Video Hardware "Gamma" control +* added Video Hardware "Trap Filter" control +* improved Mouse emulation through Wii remote +* compiled with devkitPPC r22 & libOGC 1.8.5 (includes SDHC & USB2 support through IOS58, removes DVDX support) + + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.3.1 (20/12/2008) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Gamecube/Wii] + +* improved sound engine +* modified frame synchronization (now use audio DMA interrupt) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.3.0 (14/12/2008) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* YM2612 bugfixes (MAME core): + .fixed EG Decay->Substain transition when SL & DR are minimals: fix tracks #3 and #9 in "Mega Turrican" + .fixed a bug in SSG-EG emulation code: fix Level 1 music in "Alisia Dragoon" + .modified SSG-EG Decay End Level: fix some sound effects (ChainSaw, Zap...) in "Beavis & Butthead" + .improved Detune overflow accuracy: fix very high frequency sounds in many games + .fixed registers 0x20-0x26 Reset state: fix intro music in "B.O.B" + .reverted incorrect fix with KEY ON: fix "Flamethrower" sound effect in "Alien 3" and many others +* adjusted HCounter values: fixes line flickering in "Sonic 3D" bonus stage +* adjusted VINT timing: fixes hang-up in "V.R Troopers" +* improved HBLANK flag accuracy: fixes line flickering in "Gouketsuji Ichizoku" +* fixed broken Z80 access to WRAM: fixes hang-up in "Mamono Hunter Youko" +* modified JCART emulation: fixes corrupted tracks logo in "Micro Machines 2" +* added Blargg's NTSC Filters support (NTSC video artifacts emulation) +* optimized VDP rendering core, rewrote 68k interface (memory handlers, cycle execution, interrupts): greatly improved emulation speed + +[Gamecube/Wii] + +* remove slowest libsamplerate settings under "HQ YM2612" option, only keeps SRC_LINEAR (faster) and SRC_SINC_FAST (better) +* added an option to enable/disable bilinear filtering +* rewrote video engine: improved horizontal scaling (VI+GX), improved rendering speed (direct texture mapping) +* removed embedded font, (re)enabled IPL font support: now should works for Qoob users too (thanks to emukiddid) +* fixed "Reset" button behavior, now acts more like Genesis Reset button ;-) +* patched libfat for faster SDCARD accesses (thanks to svpe) +* SRAM and SaveState filenames are now based on the ROM filename (for FAT devices only) +* various bugfixes, menu tweaks and code cleanup + +[Gamecube] + +* added 480p support in menu + +[Wii] + +* implemented fast scrolling in menu using Wiimote D-PAD +* added "Power" button support +* added USB Storage support +* Widescreen menu fix +* *new* libogc 1.7.0 features: SDHC support, Wiimote shutdown button support + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 080826 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* YM2612(MAME): fixed LFO phase update for CH3 special mode: fix sound effects in Warlock & Aladdin (thanks to AamirM) +* YM2612(MAME): fixed EG attenuation level on "KEY ON": fix Ecco 2's splash sound +* YM2612(MAME): fixed SSG-EG emulation: fix Bubba'n Stix (Track 5) and many others +* YM2612(MAME): replaced sample interpolation with libsamplerate support, High Quality mode is now more accurate +* implemented cycle-accurate HINT timings: every timing sensitive games/demos are now *finally* working fine +* fixed a bug affecting CRAM/VSRAM DMA timings +* fixed Sprite Attribute Table address mask for VRAM writes +* improved accuracy of 68k access to Z80: fix music in Pacman 2 when entering PAUSE menu +* disabled "Address Error" emulation when UMK3 hack is loaded: fix game crashing after a round ends up +* added support for some more unlicensed games: Pocket Monster, King of Fighter 98, Soul Blade (credits to Haze) +* improved Menacer emulation: fix lightgun support in Body Count & T2: The Arcade Game +* added Konami Justifier emulation: fix lightgun support in Lethal Enforcers 1 & 2 +* added Sega Mouse emulation (Populous 2, Body Count, Shangai 2, Fun'n Games, ...) + +[Gamecube/Wii] + +* added Wiimote support for Menacer/Justifier/Mouse +* added DVD support in Wii mode (no modchip required) +* added "Gun cursor" option to enable/disable gun position display +* added "Invert Mouse" option to invert Sega Mouse vertical axe (required by some games) +* improved Controller options: Wiimote/Nunchuk and Classical Controllers can now be affected separately to ANY player + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 080716 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* adjusted (again) HINT timings: fix Double Dragon 2 (game freezed), hopefully does not break anything else +* fixed broken EEPROM support for Codemaster games +* modified input update timings: fix Dungeons & Dragons * Warriors of the Eternal Sun (thanks to Notaz) +* added support for "Ultimate Mortal Kombat Trilogy" hack (max. size supported is 10MBytes) +* added (VERY) preliminar support for PICO roms (credits to Notaz for his documentation) +* improved YM2612 emulation (credits to Nemesis for his tests on real hardware): + .implemented phase overflow emulation: improved fix for special music instrument used in Comix Zone, Flashback, Ariel, Shaq Fu... + .improved SSG-EG emulation in MAME core (also based on additional code from Alone Coder) + .improved Timers emulation accuracy + .improved Enveloppe Generator accuracy + .fixed Channel 3 CSM mode emulation + .implemented sample interpolation in MAME core to emulate the chip at original frequency (HQ YM2612 mode, from gens) + +[Gamecube/Wii] + +* added automatic alphabetical filesorting (Marty Disibio) +* added ROM History for faster ROM access (Marty Disibio) +* fixed a silly input bug in "ROM Infos" & "Game Genie" menus +* modified "Hard Reset" option +* improved display sharpness in original rendering mode (H40 cell mode only), filtering is now completely disabled +* enabled overscan emulation in "STRETCH" aspect mode also +* added support for horizontal wiimote handling in Menu (automatically used when the wiimote is not pointed towards the screen) +* improved Controller options + .prevented keys reconfiguration if device is not detected + .added support for up to 8 players (ISS Pro Deluxe, ...) + .each player can be affected to a custom device (GAMECUBE Pad, WIIMOTE/NUNCHUK or CLASSIC) + .added the ability to use classic controller & wiimote pad from the same port separately + .modified "soft-reset" key on the Wiimote to avoid "accidental" resets (now press Buttons + & * simultaneously) + .added MODE button mapping: use "START+Z" on gamepad or "Button Minus" on wiimote/classic (not reconfigurable) + .added automatic configuration save for controller options + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 080601 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* improved HCounter accuracy: fix graphic glitches in "Striker (Europe)" +* improved HINT timing accuracy: fix flickering in "Zero The Kamikaze Squirrel (USA)" +* improved rendering accuracy when backdrop color is modified during HBLANK (Road Rash I/II/III) +* fixed broken Game Genie support + +[Gamecube/Wii] + +* added full horizontal scaling (up to 720 pixels) when using "stretch" aspect mode (use Xscale to increase width) +* added progressive mode support (480p) in menu also +* added automatic SRAM/FreezeState support (OFF by default, check "system options") +* added automatic configuration file support +* /genplus/saves is now automatically created if it does not exist +* use libfat automatic SDCARD detection: default slot is now always used when accessing SDCARD +* assigned Reset Button to Genesis Soft-Reset + +[Wii] + +* added automatic TV mode detection (from SYSCONF), no more PAL60 version needed +* added option to return to Wii System Menu +* fixed "TP reload" option: now compatible with HB channel +* removed SD-Gekko support (Wii slot becomes default slot) +* added Wii SD slot support for SRAM & FreezeState files +* added Wiimote, Nunchuk & Classic controllers support through libwiiuse (see User Manual for default keys) +* added customizable key mapping (for each configurations: wiimote only, wiimote+nunchuk or classic) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 080419 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* modified VINT timings a little bit: fix lockup during Desert Strike's intro +* corrected 68k interrupts handling: fix graphic glitches in Darius II/Sagaia + +[Gamecube/Wii] + +* fixed 60Hz "Bilinear" rendering mode (was broken in last release) +* fixed issue with the 1st file when browsing SDCARD through SD-Gekko +* fixed GX initialization: fix "freeze" issue that occured sometime when starting a game +* added "Wii Reboot" option +* added PAL 50hz support in menu (black borders) +* added progressive rendering mode support (480p) in Wii mode (not supported by the PAL60 version, use the other one !) +* compiled with a modified libogc: should definitely fix the PAL "red screen" issue for RGB-cable users (still use the PAL60 version !) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 080406 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* updated SVP core: fix some perspective issues in Virtua Racing (thanks to Notaz) +* added internal SAT update during VRAM Fill: fix unmasked sprites during Battletech's intro +* fixed m68k core issues with gcc 4.2.3: fix Xperts, Lemmings 2, M1 Abrams Battle Tank +* forced YM2612 Enveloppe update: fix intro music in Batman&Robin (thanks to Aamir) + +[Gamecube/Wii] + +* removed not working DVD features (Wii mode only) +* fixed Timers with PAL roms +* added EURGB60 TV mode support: fix "red screen" issue with PAL Wii when using RGB cable +* added PAL50 TV mode support (PAL and NTSC roms), see video options +* added "TP reload" option, use "System Reboot" (Wii mode only) +* added Front SD rom loading support with LFN & subdirectory browsing (Wii mode only) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 080301 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* added SVP emulation: Virtua Racing is now emulated (big thanks to Notaz and TascoDeluxe) +* fixed VDP registers behaviour when VDP Mode 4 is enabled: fix Bass Masters Classic Pro, Captain Planet & The Planeeters +* corrected a bug in DMA Fill operation: fix James Pond 3, Rockman World/Megaman Willy Wars (corrupted VRAM) +* corrected typo errors in CPU cycle counters update: fix optiom screen music in "College Slam" and probably others games. +* added preliminary support of undocumented YM2612 bug: fixes soundtracks of Shaq Fu, Spiderman, Comix Zone, Ariel and some others +* added support for mappers & copy protection devices used in many unlicensed/pirate cartridges (see cart_hw.c for details) +* rewrote memory handlers for better modularity and some (little) speedup +* reduced Savestate size + +[Gamecube] + +* compiled with last LibOGC (20080228): fix issues when unplugging controller, support for Wii mode (see release.txt) +* added "hard-coded" IPL font (no more direct access to BOOTROM): fix font problem for Qoob users +* added SDCARD Slot B support for loading Roms +* removed unused MAME PSG Core +* added 'Force DTACK' option for prototype games usually hanging on real hardware (example: Sonic Crackers) +* added an option to underclock SVP core (with default cycle count, Virtua Racing actually does not run fullspeed in GC mode) +* fixed frame timing in PAL mode +* fixed analog stick sensitivity + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 080107 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* fixed interleaved rom detection: roms with .smd extension should now work fine +* fixed a recently introduced bug in VDP registers writes: fixes bad colors in Toy Story (intro) +* updated list of games using EEPROM: added Sports Talk Baseball (internal memory check fixed) and Brian Lara Cricket +* fixed VINT flag update when VINT is disabled: fixes NCAA College Football +* adjusted DMA timings in H32 mode: fixes flickering in Out of this World, Kawasaki Superbike Challenge & Formula One +* adjusted line rendering and HBLANK timings: fixes flickering in Nigel Mansell's World Championship Racing, Deadly Moves/Power Athlete +* fixed unmapped ROM reads through Z80 Bank: fixes Zombie High (Proto) +* added support for custom ROM/RAM mapping used by Game no Kanzume Otokuyou + +[Gamecube] + +* fixed broken SDCARD support for SRAM and Savestate files + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 071230 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Gamecube] + +* fixed ROM injector base address (DATA section 1) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 071228 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* many sourcecode cleanup and optimization +* completely rewrote EEPROM emulation: now support all known EEPROM types (24C01-24C65) and mappers (Sega, Acclaim, EA, Codemasters) +used in a few games (now use internal game database) as external RAM. This should at least fix save support in the following games: + . NBA Jam (alternate Acclaim mapper) + . College Slam, Frank Thomas Big Hurt Baseball (24C65 type) + . NHLPA Hockey 93, Rings of Power (EA mapper) + . Micro Machines serie, Brian Lara Cricket 96/Shane Warne Cricket (Codemasters mapper) +* external RAM is now initialized to 0xFF by default: fix Micromachines 2, Dino Dini Soccer +* fixed SRAM 16-bits memory handlers: fix some Sega Sports and EA Sports games (NFL95, NBA Action 95, NHL97, NHL98,...) +* modified WRITE_xxx & READ_xxx macros for better portability and faster memory access on BIG ENDIAN platform +* completely rewrote BIG ENDIAN support in render.c and vdp.c: rendering should be a little faster +* rewrote ROM bankswitch emulation (Super Street Fighter II): ROM access are faster, using memory pointers instead of reading ROM copy from ARAM +* fixed leftmost Window/PlaneA column render and implemented Window bug (as described by Charles Mc Donald) +* improved "Sprite Limit" and "Sprite Collision" detection accuracy +* modified RGB565 Color Palette to use the full available color range (0-31;0-63) +* implemented "cycle accurate" HV Interrupt timings: fix Sesame's Street Counting Cafe, Legend of Galahad (intro) +* improved VDP access timings accuracy (added FIFO emulation): fix Double Clutch +* improved DMA timings accuracy: fix Winter Olympics (E), Arch Rivals and probably more +* fixed HCounter again: Road Rash serie (I,II,III) don't need timing hacks anymore +* fixed VCounter in Interlaced 2 mode: fix Combat Cars "VS-Mode" +* improved Interlaced 2 mode (double resolution) rendering: Sonic 2, Combat Cars ("VS-Modes") look far better +* added TMSS BIOS support (optional) +* rewrote part of the YM2162 MAME's core: fixed internal FM timers handling, removed non-YM2612 emulation code and unused multiple cpu support +* implemented "cycle accurate" FM timers & sound samples rendering +* improved Z80 Interrupt timing accuracy: fix Sonic 3 music slowdowns +* updated Z80 & 68000 cores to last MAME versions +* improved Soft Reset emulation: X-Men 2 and Eternal Champions (random character selection) now work more like on real hardware. +* added full overscan emulation (vertical & horizontal borders) for "pixel perfect" aspect ratio (tested against a real genesis) + +[Gamecube] + +* fixed rom checksum calculation (only used for rom information) +* some modifications in GX rendering code. +* added support for original Genesis/Megadrive NTSC & PAL video modes: this makes games looking exactly as on original hardware (progressive rendering with reduced resolution) +* added "Aspect" option to switch between ORIGINAL (aspect ratio is fixed and borders are emulated) and MANUAL SET (horizontal and vertical scaling can be manually configured, borders are not emulated) +* added "Overscan" option to disable the original borders color and always use black borders (only used when ORIGINAL Aspect mode is enabled) +* added support for up to 720 pixels horizontal resolution (needed for proper aspect ratio emulation) +* added "TV Mode" option to enable automatic switching to PAL(50Hz) TV mode when the Genesis runs in PAL mode +* added "Xshift" & "Yshift" settings to let you adjust display area position while keeping the original aspect ratio +* added option to disable/enable SSG-EG support in FM cores: this special mode is indeed not properly emulated and some games might sound wrong when enabled +* removed "CPU Type" option, you can also now force Region (JAP/EUR/USA) without reseting the game, choose USA or JAP for 60hz, EUR for 50hz, this can be useful to bypass game region protection at startup. + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070720 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* corrected TeamPlayer support: fix multiplayer in Gauntlet 4 (Sept. version), Pengo and a lot of others +* added J-Cart support: enable multiplayer in Codemasters games (Pete Sampras, Micromachines games, Super Skidmarks) +* added serial EEPROM autodetection: fix games with bad SRAM informations in header (NBA Jam TE) +* added SVP faking: display 2D graphics in Virtua Racing (the game is however still unplayable) +* added support for more internal IO registers: fixe some unlicensed games (Wisdom Tree games...) +* added preliminary support for unmapped protection device: fix some unlicensed games with special built-in hardware (Squirell King, Lion King 2...) +* added "Soft Reset" combo (in game, use L+Z triggers): this should be like pressing the RESET button on a real Genesis and this is required + in some games to enable special features or even complete the game (ex: X-Men). + +[Gamecube] + +* added separate configuration for PortA/PortB inputs (GAMEPAD, MULTITAP or NONE, see Joypad Config): this let you setting + PORTB as unplugged, which is needed in some games to access special modes or enable cheat codes (Alien Storm, X-Men...) +* Freezestate & SRAM files are now compressed (using zlib) +* FreezeState & SRAM files can now be saved/loaded to/from SDCARD: located in /genplus/saves/ from the root of your SDCARD +* changed initial ROMS directory for SDCARD user: now looking for /genplus/roms/ from the root of your SDCARD +* added user-transparent SRAM autoload (detection order is MCARD then SDCARD, SLOTA then SLOTB) +* "System reboot" is now used for console reboot and SD/PSO reload (if detected) +* added new font: now use original IPL font, extracted from Bootrom +* modified controls when going into the rom selection menu (DVD or SDCARD): + . use B button to go up one directory + . use Z button to quit the file selection menu + . use L/R triggers to go down/up one full page + . use Left/Right buttons or Analog stick to scroll the selected entry's filename when it can't be full displayed +* various menu rearrangment, minor bugfixes & sourcecode cleanup + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070621 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* added Multitap support (EA 4-Way Play and Sega Teamplayer): allowed up to four players in games supporting those peripherals +* added partial Sega Menacer lightgun support: automatically set when detecting the 6-in-1 Menacer game + +[Gamecube] + +* added 4.7GB DVD support for WII drives (the maximal allowed size for Gamecube DVD is still 1.35GB) +* removed MPAL video timings, always use 60Hz NTSC: fix display problems for PAL wii users (no more PAL50 version needed) +* added Console Reboot option in main menu (IPL Reboot) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070518 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* you can now switch between FM cores without reseting the game. FM registers value are automatically restored when switching. +* removed the previous VINT timings modification because it brokes some games (Rocket Knight, Thunderforce III,...) +* added automatic Timing configuration (VDP latency, VINT timing & alternate Line Timing) at game loading, based upon specific romname detection. +This means you can still modify some of these options afterwards but they are now automatically set/unset when loading a game which need +special timing fixes. These fixes are also automatically desactivated when the current game doesn't need them. +For information, games that are actually detected and need special timings to run properly are: + .Legend of Galahad & Road Rash series (single line not rendered properly) + .Sesame Street Counting Cafe (don't boot) + .Chaos Engine/Soldiers of Fortune (graphic glitches on scrolling) + +[Gamecube] + +* modified PAL framesync a little bit: the 20ms period is now applied between the start of 2 consecutive frames, +no more between the end of the previous and the start of the next one, which seems more correct to me + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070508 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* VINT timings are now a little more accurate: fixes Sesame's Street Counting Cafe +* SN76496 MAX_OUTPUT back to normal +* modified FB_WNOISE value in SN76496 core according to John Kortink's last informations +* added support for Maxim's PSG core, same as used in SMSPLUS (it becomes the default PSG core) +* updated FM core to the latest MAME version +* corrected DAC output level (fixes voices and some special FX being too low) +* added support for Gens YM2612 (FM) core (MAME's one still remains default FM core) + +[Gamecube] + +* corrected L & R buttons assignment: fixes Genesis X & Z buttons being inverted +* added configurable preamplification for each sound cores (see Emulator Options) +* added some other configurable sound options (boost overall volume, FM improvment for Gens YM2612) + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070411 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* corrected MAX_OUTPUT value in SN76496 core: fix PSG sound (SFX) volume +* removed unused sound buffer allocation + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070326 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Gamecube] + +* added DVD automount: automatically call libogc DVD_Mount function if ISO PVD reading failed (idea taken from softdev's last neocdredux release). This may be useful for loading roms from a DVD after booting from SDLOAD or after stopping DVD motor. +* added "DVD motor off" feature, like in others emulators +* corrected Memory Card mounting function: EXI_ProbeReset() function was never called if the first mounting attempt failed. Should fix some of the "Unable to mount memory card" errors. + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070322 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Gamecube] + + * added SDCARD subdirectory browsing and LFN (255 char. max) support + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070317 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + + * Color RAM update now always reset color 0 to border color (fix color glitches in Mortal Kombat,...) (thanks to Noop's for the idea) + +[Gamecube] + + * remove some rendering unused code (only used by DOS version of genesis plus) for little speedup + * added an option to enable alternate line rendering timing (fix single line error in Road Rash series and Legend of Galahad's Intro) + * added last Softdev's modifications (normalised memory access and ASM GU functions used intead of 'C' ones) for some speedup + * updated gcaram.c to be compatible with last libogc version + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070309 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* little rendering code speedups +* modified HV counter tables (fix graphic glitches in Skitchin's sky, Lotus 2 Recs, Panorama Cotton, Dashin Desperados & maybe more) +* completely rewrote DMA timings emulation so that it works for all games (no more cpu freezing) +* added all DMA tranfer rates handling for each three DMA modes and added dma busy flag emulation +* modified interrupts handling on VDP register #0 and #1 writes (fix Lemmings status bar) +* added VDP RAM write latency (fix Chaos Engine/Soldier of Fortune gfx glitches) +* modified FM timers handling a bit (fix Vectorman2 music) +* corrected Sprite Limit rendering (fix Sonic 1 & Micromachines 2 title screens) +* corrected IO Registers writes (fix Decap' Attack controls, no more need for alternate input) +* corrected 6 Buttons Pad emulation (fix 6buttons detection in Mortal Kombat 3, Comix Zone and other 6-buttons compatible games) +* modified sound mixing a bit according to Generator sourcecode (FM and PSG ratios seems more correct) +* added separate CPU Region (USA, Europe, Japan,...) & Speed (PAL or NTSC) choice in menu options +* modified main frame synchro in PAL mode (fix sound glitch in this mode), thanks to Softdev for the solution +* added savestates support (go to SRAM menu, memory card supports only) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX release 070207 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* fm timers fixed (fix missing music in Castle of Illusion, Quackshot, Undead Line, Wonderboy in Monster Lair, Cal 50, Turbo Outrun, Thundeforce 4 and maybe more) +* added complete EEPROM emulation (save support now works fine in Wonderboy5, Megaman Willy Wars, NBA Jam...) (credits to Notaz, adapted from Picodrive code) +* added preliminar dma timing emulation (fix bottom screen in Legend of Galahad) (credits to Notaz, adapted from Picodrive code) +* hack: clear Vint pending after Hint (INT level 4) acknowledge (fix Fatal Rewind) +* hack: modify read_bus16 to return a random value (fake fetch) (fix Time Killers) +* modified cpu execution timings, with more correct hblank and interrupts timing (fix ISS Deluxe, Double Dragon 2 and certainly more) (Based on Gens code) +* modified busreq mechanism: better synchro between z80 & 68k (no need to dejitter anymore) (Based on Gens code) +* added sprite collision detection (fix Strider 2) +* modified dma fill operation for big endian platform (fix Contra Hardcorps gfx garbage) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX WIP 1.2 (Softdev) +--------------------------------------------------------------------------------------------------------- + +[Gamecube] + +* Added partial zip support (unzip.c) + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX WIP 1.1 (Softdev) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* sio.c added +* Added six button pad support from x86 Gens +* Additional changes based on Charles MacDonald's gen-hw.txt + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX WIP 1 - 7 March 2006 (Softdev) +--------------------------------------------------------------------------------------------------------- + +[Core] + +* Updated SN76496 driver + +[Gamecube] + +* Added GX Hardware Scaling + + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX WIP 0 (Softdev) +--------------------------------------------------------------------------------------------------------- + +[Gamecube] + +* initial port based on Genesis Plus 1.2a from Charles McDonald (http://cgfm2.emuviews.com/) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..1de18c2 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,621 @@ + +Unless otherwise explicitly stated, all code in Genesis Plus GX is released +under the following license: + +Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles MacDonald +Some portions copyright Nicola Salmoria and the MAME team +All rights reserved. + +Copyright (c) 2007-2013 Eke-Eke +All rights reserved. + +Redistribution and use of this code or any derivative works are permitted +provided that the following conditions are met: + +* Redistributions may not be sold, nor may they be used in a commercial +product or activity. + +* Redistributions that are modified from the original source must include the +complete source code, including the source code for all components used by a +binary built from the modified sources. However, as a special exception, the +source code distributed need not include anything that is normally distributed +(in either source or binary form) with the major components (compiler, kernel, +and so on) of the operating system on which the executable runs, unless that +component itself accompanies the executable. + +* Redistributions must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other +materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +---------------------------------------------------------------------------------------- + +TREMOR library is distributed under the following license: + +Copyright (c) 2002, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------------------------------------------------------------------------------- + + +NTSC Filter and Blip Buffer libraries are distributed under the +terms of the GNU Lesser General Public License (LGPL) + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + +---------------------------------------------------------------------------------------- + +Gamecube & Wii ports are linked with LIBASND library and includes code distributed under +the following license: + +Copyright (c) 2008 Hermes +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. +- The names of the contributors may not be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +---------------------------------------------------------------------------------------- + + + diff --git a/README.md b/README.txt similarity index 100% rename from README.md rename to README.txt From 7d032ebedc5b5e6d5a0c01105670a9c6d2bcc74a Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 8 Sep 2013 17:29:31 +0200 Subject: [PATCH 12/39] fixed README --- README.txt => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.txt => README.md (100%) diff --git a/README.txt b/README.md similarity index 100% rename from README.txt rename to README.md From 606b2d688d73bc16b5a3605b3d5a74fbbd3b86ab Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 8 Sep 2013 17:35:49 +0200 Subject: [PATCH 13/39] nitpicking... --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 984d1f7..4ba9718 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ About --------- -Genesis Plus GX is an open-source & portable Sega Mega Drive / Genesis emulator,now also emulating SG-1000, Master System, Game Gear and Sega/Mega CD. +Genesis Plus GX is an open-source & portable Sega Mega Drive / Genesis emulator, now also emulating SG-1000, Master System, Game Gear and Sega/Mega CD hardware. The source code is based on Genesis Plus 1.3, originally developped by Charles MacDonald (http://cgfm2.emuviews.com). -It has been heavily modified, with respect to initial goals and design, in order to improve accuracy of emulation, implementing new features and adding support for extra peripherals, cartridge & system hardwares. +It has been heavily modified, with respect to initial goals and design, in order to improve accuracy of emulation, implementing new features and adding support for extra peripherals, cartridge & systems hardware. The result is that Genesis Plus GX is now more a continuation of the original project than a simple port, providing very accurate emulation and 100% compatibility with Genesis / Mega Drive, Sega / Mega CD, Master System, Game Gear & SG-1000 software (including all unlicensed or pirate known dumps), also emulating backwards compatibility modes when available. From 529112f321fc5a86111ceaab4d74a61c1bdbe5de Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 20 Oct 2013 20:31:51 +0200 Subject: [PATCH 14/39] [Core/MD] added support for Thunderbolt II (unlicensed) copy protection --- core/cart_hw/md_cart.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/core/cart_hw/md_cart.c b/core/cart_hw/md_cart.c index b49f310..c7ddf58 100644 --- a/core/cart_hw/md_cart.c +++ b/core/cart_hw/md_cart.c @@ -46,7 +46,7 @@ #include "eeprom_spi.h" #include "gamepad.h" -#define CART_CNT (54) +#define CART_CNT (55) /* Cart database entry */ typedef struct @@ -176,6 +176,8 @@ static const md_entry_t rom_database[CART_CNT] = {0xfb40,0x4bed,0x40,0x40,{{0x00,0xaa,0x00,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x400002,0x000000,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, /* 16 Tiles Mahjong II (uses 16-bits reads) */ {0xffff,0x0903,0x40,0x40,{{0x00,0x00,0xc9,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x400004,0x000000},0,0,NULL,NULL,default_regs_r_16,NULL}}, +/* Thunderbolt II (uses 16-bits reads) */ + {0x0000,0x1585,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,NULL,NULL,default_regs_r_16,NULL}}, /* Super Bubble Bobble */ @@ -299,7 +301,7 @@ void md_cart_init(void) } /* Sonic & Knuckles */ - if (strstr(rominfo.international,"SONIC & KNUCKLES") != NULL) + if (strstr(rominfo.international,"SONIC & KNUCKLES")) { /* disable ROM mirroring at $200000-$3fffff (normally mapped to external cartridge) */ size = 0x400000; @@ -336,7 +338,7 @@ void md_cart_init(void) } /* support for Quackshot REV 01 (real) dump */ - if ((strstr(rominfo.product,"00004054-01") != NULL) && (cart.romsize == 0x80000)) + if (strstr(rominfo.product,"00004054-01") && (cart.romsize == 0x80000)) { /* $000000-$0fffff: first 256K mirrored (A18 not connected to ROM chip, A19 not decoded) */ for (i=0x00; i<0x10; i++) @@ -380,7 +382,7 @@ void md_cart_init(void) SVP CHIP ***********************************************/ svp = NULL; - if (strstr(rominfo.international,"Virtua Racing") != NULL) + if (strstr(rominfo.international,"Virtua Racing")) { svp_init(); @@ -400,14 +402,14 @@ void md_cart_init(void) J-CART ***********************************************/ cart.special = 0; - if (((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military */ - ((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */ - ((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */ - ((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */ - ((strstr(rominfo.product,"XXXXXXXX") != NULL) && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */ - ((strstr(rominfo.product,"T-123456") != NULL) && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */ - ((strstr(rominfo.product,"T-120066") != NULL) && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/ - (strstr(rominfo.product,"T-120096") != NULL)) /* Micro Machines 2 */ + if ((strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military */ + (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */ + (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */ + (strstr(rominfo.product,"00000000") && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */ + (strstr(rominfo.product,"XXXXXXXX") && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */ + (strstr(rominfo.product,"T-123456") && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */ + (strstr(rominfo.product,"T-120066") && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/ + strstr(rominfo.product,"T-120096")) /* Micro Machines 2 */ { if (cart.romsize <= 0x380000) /* just to be sure (checksum might not be enough) */ { @@ -567,7 +569,7 @@ void md_cart_init(void) } /* detect specific mappers */ - if (strstr(rominfo.domestic,"SUPER STREET FIGHTER2") != NULL) + if (strstr(rominfo.domestic,"SUPER STREET FIGHTER2")) { /* SSF2 mapper */ cart.hw.bankshift = 1; @@ -575,7 +577,7 @@ void md_cart_init(void) /* specific !TIME handler */ cart.hw.time_w = mapper_ssf2_w; } - else if (strstr(rominfo.product,"T-5740") != NULL) + else if (strstr(rominfo.product,"T-5740")) { /* T-5740XX-XX mapper */ cart.hw.bankshift = 1; @@ -589,7 +591,7 @@ void md_cart_init(void) /* initialize SPI EEPROM board */ eeprom_spi_init(); } - else if ((strstr(rominfo.ROMType,"SF") != NULL) && (strstr(rominfo.product,"001") != NULL)) + else if (strstr(rominfo.ROMType,"SF") && strstr(rominfo.product,"001")) { /* SF-001 mapper */ m68k.memory_map[0x00].write8 = mapper_sf001_w; @@ -599,7 +601,7 @@ void md_cart_init(void) /* no !TIME handler */ cart.hw.time_w = m68k_unused_8_w; } - else if ((strstr(rominfo.ROMType,"SF") != NULL) && (strstr(rominfo.product,"002") != NULL)) + else if (strstr(rominfo.ROMType,"SF") && strstr(rominfo.product,"002")) { /* SF-002 mapper */ m68k.memory_map[0x00].write8 = mapper_sf002_w; @@ -609,7 +611,7 @@ void md_cart_init(void) /* no !TIME handler */ cart.hw.time_w = m68k_unused_8_w; } - else if ((strstr(rominfo.ROMType,"SF") != NULL) && (strstr(rominfo.product,"004") != NULL)) + else if (strstr(rominfo.ROMType,"SF") && strstr(rominfo.product,"004")) { /* SF-004 mapper */ m68k.memory_map[0x00].write8 = mapper_sf004_w; From f4014c3ef1db0e5e392152062a343b4c8ef1b90e Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 20 Oct 2013 20:38:31 +0200 Subject: [PATCH 15/39] [Core/VDP] improved H-Counter accuracy in H32 mode (modified in r457 for Sonic 3D Blast bonus stage, not needed anymore) --- core/hvc.h | 91 +++++++++++++++++++++++++++++++-------------------- core/system.h | 4 +-- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/core/hvc.h b/core/hvc.h index 75684a3..9533626 100644 --- a/core/hvc.h +++ b/core/hvc.h @@ -143,21 +143,38 @@ /* */ /* H-counter timings in H32 & H40 modes (starts from HINT) */ /* */ -/* There are exactly 3420 Master Clock counts per raster line. */ +/* There are normally 3420 Master Clock counts per raster line */ +/* with 342 dots/line in H32 mode & 420 dots/line in H40 mode. */ /* */ -/* in H32 mode, dot clock is divided from MCLK (MCLK/10). */ -/* in H40 mode, dot clock is divided from EDCLK (EDCLK/2). */ +/* in H32 mode, dot clock is divided from MCLK (MCLK/10) */ +/* in H40 mode, dot clock is divided from EDCLK (EDCLK/2) */ /* */ /* EDCLK (external dot clock ?) is generated outside the VDP: */ -/* During HSYNC, it is oscillating between MCLK/10 and MCLK/8, */ +/* When HSYNC is low, EDCLK varies between MCLK/10 and MCLK/8, */ /* otherwise it is fixed to MCLK/8. */ /* */ +/* Notes: */ +/* (1) VDP register 12 bit 7 enables use of EDCLK when set */ +/* (2) VDP register 12 bit 5 forces HSYNC high when set */ +/* (3) H32 or H40 mode is selected with VDP register $0C bit 0 */ +/* and can be set independently from above settings */ +/* */ +/* On real hardware, non-standard timings can be obtained by */ +/* modifying those settings (for example, dot clock can be set */ +/* to MCLK/8 in both modes if HSYNC output is disabled and if */ +/* EDCLK input is enabled in H32 mode / disabled in H40 mode), */ +/* resulting in slightly different H-counter and VDP timings. */ +/* */ +/* Genesis Plus GX timings always assume standard settings i.e */ +/* HSYNC output always enabled and EDCLK input enabled in H40 */ +/* mode / disabled in H32 mode. */ +/* */ /***************************************************************/ static const uint8 cycle2hc32[3420] = { - /* end of active display (16 pixels -> 160 Mcycles) , H interrupt triggered, Vcounter increment */ - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + /* end of active display (14 pixels -> 140 Mcycles) , H interrupt triggered, Vcounter increment */ + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88, @@ -165,10 +182,11 @@ static const uint8 cycle2hc32[3420] = 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + /* right border (14 pixels -> 140 Mcycles) */ + 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, @@ -176,20 +194,21 @@ static const uint8 cycle2hc32[3420] = 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + + /* right blanking (9 pixels -> 90 Mcycles), VDP status HBLANK flag set */ + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - - /* right blanking (9 pixels -> 90 Mcycles) , VDP status HBLANK flag set */ 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, - 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, - 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, - - /* horizontal sync (26 pixels -> 260 Mcycles) */ - 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xec, 0xec, + + /* horizontal sync (26 pixels -> 260 Mcycles) */ + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, @@ -204,11 +223,11 @@ static const uint8 cycle2hc32[3420] = 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, - 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, - + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + /* left blanking (24 pixels -> 240 Mcycles) */ - 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, @@ -216,30 +235,31 @@ static const uint8 cycle2hc32[3420] = 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - /* V interrupt triggered (MD mode) */ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, + /* V interrupt triggered (MD mode) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + /* left border (13 pixels -> 130 Mcycles) , VDP status HBLANK flag cleared */ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - - /* remaining active display (240 pixels -> 2400 Mcycles) */ - 0x0d, 0x0d, 0x0d, 0x0d, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + + /* remaining active display (252 pixels -> 2520 Mcycles) */ + + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, @@ -389,8 +409,7 @@ static const uint8 cycle2hc32[3420] = 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84 }; static const uint8 cycle2hc40[3420] = diff --git a/core/system.h b/core/system.h index 8cdae62..b679421 100644 --- a/core/system.h +++ b/core/system.h @@ -64,8 +64,8 @@ #define MCYCLES_PER_LINE 3420 /* Horizontal timing offsets when running in Z80 mode */ -#define SMS_CYCLE_OFFSET 520 -#define PBC_CYCLE_OFFSET 550 +#define SMS_CYCLE_OFFSET 530 +#define PBC_CYCLE_OFFSET 560 typedef struct { From adae91bd65996b11d6f8a8c9161bb2113c8c6c15 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 20 Oct 2013 20:41:44 +0200 Subject: [PATCH 16/39] [Core/VDP] improved FIFO timings accuracy (fixes "Overdrive" Demo) --- core/system.c | 6 +- core/vdp_ctrl.c | 155 +++++++++++++++++++++++++++++------------------- core/vdp_ctrl.h | 2 +- 3 files changed, 99 insertions(+), 64 deletions(-) diff --git a/core/system.c b/core/system.c index 77fb6f9..38bf293 100644 --- a/core/system.c +++ b/core/system.c @@ -357,7 +357,7 @@ void system_frame_gen(int do_skip) /* reset VDP FIFO */ fifo_write_cnt = 0; - fifo_lastwrite = 0; + fifo_slots = 0; /* update 6-Buttons & Lightguns */ input_refresh(); @@ -703,7 +703,7 @@ void system_frame_scd(int do_skip) /* reset VDP FIFO */ fifo_write_cnt = 0; - fifo_lastwrite = 0; + fifo_slots = 0; /* update 6-Buttons & Lightguns */ input_refresh(); @@ -1032,7 +1032,7 @@ void system_frame_sms(int do_skip) /* reset VDP FIFO */ fifo_write_cnt = 0; - fifo_lastwrite = 0; + fifo_slots = 0; /* update 6-Buttons & Lightguns */ input_refresh(); diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index 7ec7d4f..908997b 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -85,8 +85,8 @@ uint8 vdp_pal; /* 1: PAL , 0: NTSC (default) */ uint16 v_counter; /* Vertical counter */ uint16 vc_max; /* Vertical counter overflow value */ uint16 lines_per_frame; /* PAL: 313 lines, NTSC: 262 lines */ -int32 fifo_write_cnt; /* VDP writes fifo count */ -uint32 fifo_lastwrite; /* last VDP write cycle */ +int32 fifo_write_cnt; /* VDP FIFO write count */ +uint32 fifo_slots; /* VDP FIFO access slot count */ uint32 hvc_latch; /* latched HV counter */ const uint8 *hctab; /* pointer to H Counter table */ @@ -134,9 +134,10 @@ static uint16 sat_addr_mask; /* Index bits of SAT */ static uint16 dma_src; /* DMA source address */ static uint16 dmafill; /* DMA Fill setup */ static uint32 dma_endCycles; /* 68k cycles to DMA end */ -static uint32 fifo_latency; /* CPU access latency */ static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */ static uint16 fifo[4]; /* FIFO buffer */ +static int fifo_byte_access; /* FIFO byte access flag */ +static uint32 fifo_cycles; /* FIFO next access cycle */ /* set Z80 or 68k interrupt lines */ static void (*set_irq_line)(unsigned int level); @@ -227,8 +228,10 @@ void vdp_reset(void) im2_flag = 0; interlaced = 0; fifo_write_cnt = 0; - fifo_lastwrite = 0; - cached_write = -1; + fifo_cycles = 0; + fifo_slots = 0; + cached_write = -1; + fifo_byte_access = 1; ntab = 0; ntbb = 0; @@ -259,9 +262,6 @@ void vdp_reset(void) /* default Window clipping */ window_clip(0,0); - /* default FIFO timings */ - fifo_latency = 214; - /* reset VDP status (FIFO empty flag is set) */ if (system_hw & SYSTEM_MD) { @@ -478,9 +478,8 @@ int vdp_context_load(uint8 *state) load_param(&cached_write, sizeof(cached_write)); - /* restore FIFO timings */ - fifo_latency = (reg[12] & 1) ? 190 : 214; - fifo_latency <<= ((code & 0x0F) < 0x03); + /* restore FIFO byte access flag */ + fifo_byte_access = ((code & 0x0F) < 0x03); /* restore current NTSC/PAL mode */ if (system_hw & SYSTEM_MD) @@ -769,20 +768,12 @@ void vdp_68k_ctrl_w(unsigned int data) /* FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch, Sol Deace) -------------------------------------------------------------------------- - - CPU access per line is limited during active display: - H32: 16 access --> 3420/16 = ~214 Mcycles between access - H40: 18 access --> 3420/18 = ~190 Mcycles between access - - This is an approximation: on real hardware, access slots are fixed. - - Each VRAM access is byte wide, so one VRAM write (word) need twice cycles. + Each VRAM access is byte wide, so one VRAM write (word) need twice cycles. Note: Invalid code 0x02 (register write) apparently behaves the same as VRAM access, although no data is written in this case (fixes Clue menu) */ - fifo_latency = (reg[12] & 1) ? 190 : 214; - fifo_latency <<= ((code & 0x0F) < 0x03); + fifo_byte_access = ((code & 0x0F) <= 0x02); } /* Mega Drive VDP control port specific (MS compatibility mode) */ @@ -1221,8 +1212,11 @@ unsigned int vdp_68k_ctrl_r(unsigned int cycles) { unsigned int temp; - /* Update FIFO flags */ - vdp_fifo_update(cycles); + /* Update FIFO status flags if not empty */ + if (fifo_write_cnt) + { + vdp_fifo_update(cycles); + } /* Update DMA Busy flag */ if ((status & 2) && !dma_length && (cycles >= dma_endCycles)) @@ -1980,9 +1974,6 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) /* Update clipping */ window_clip(reg[17], 1); - - /* Update fifo timings */ - fifo_latency = 190; } else { @@ -1997,14 +1988,8 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) /* Update clipping */ window_clip(reg[17], 0); - - /* Update FIFO timings */ - fifo_latency = 214; } - /* Adjust FIFO timings for VRAM writes */ - fifo_latency <<= ((code & 0x0F) < 0x03); - /* Active display width modified during HBLANK (Bugs Bunny Double Trouble) */ if ((v_counter < bitmap.viewport.h) && (cycles <= (mcycles_vdp + 860))) { @@ -2063,38 +2048,84 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) } } - /*--------------------------------------------------------------------------*/ -/* FIFO update function (Genesis mode only) */ +/* FIFO emulation (Mega Drive VDP specific) */ +/* ---------------------------------------- */ +/* */ +/* CPU access to VRAM, CRAM & VSRAM is limited during active display: */ +/* H32 mode -> 16 access per line */ +/* H40 mode -> 18 access per line */ +/* */ +/* with fixed access slots timings detailled below. */ +/* */ +/* Each VRAM access is byte wide, so one VRAM write (word) need two slots. */ +/* */ /*--------------------------------------------------------------------------*/ static void vdp_fifo_update(unsigned int cycles) { - if (fifo_write_cnt > 0) + int slots, count = 0; + + const int *fifo_timing; + + const int fifo_cycles_h32[16+2] = { - /* Get number of FIFO reads */ - int fifo_read = ((cycles - fifo_lastwrite) / fifo_latency); + 230, 510, 810, 970, 1130, 1450, 1610, 1770, 2090, 2250, 2410, 2730, 2890, 3050, 3350, 3370, + MCYCLES_PER_LINE + 230, MCYCLES_PER_LINE + 510 + }; - if (fifo_read > 0) - { - /* Process FIFO entries */ - fifo_write_cnt -= fifo_read; + const int fifo_cycles_h40[18+2] = + { + 352, 820, 948, 1076, 1332, 1460, 1588, 1844, 1972, 2100, 2356, 2484, 2612, 2868, 2996, 3124, 3364, 3380, + MCYCLES_PER_LINE + 352, MCYCLES_PER_LINE + 820 + }; - /* Clear FIFO full flag */ - status &= 0xFEFF; - /* Check remaining FIFO entries */ - if (fifo_write_cnt <= 0) - { - /* Set FIFO empty flag */ - status |= 0x200; - fifo_write_cnt = 0; - } - - /* Update FIFO cycle count */ - fifo_lastwrite += (fifo_read * fifo_latency); - } + /* number of access slots up to current line */ + if (reg[12] & 0x01) + { + fifo_timing = fifo_cycles_h40; + slots = 18 * (cycles / MCYCLES_PER_LINE); } + else + { + fifo_timing = fifo_cycles_h32; + slots = 16 * (cycles / MCYCLES_PER_LINE); + } + + /* number of access slots within current line */ + cycles = cycles % MCYCLES_PER_LINE; + while (fifo_timing[count] <= cycles) + { + count++; + } + + /* number of processed FIFO entries since last access */ + slots = (slots + count - fifo_slots) >> fifo_byte_access; + + if (slots > 0) + { + /* process FIFO entries */ + fifo_write_cnt -= slots; + + /* Clear FIFO full flag */ + status &= 0xFEFF; + + if (fifo_write_cnt <= 0) + { + /* No more FIFO entries */ + fifo_write_cnt = 0; + + /* Set FIFO empty flag */ + status |= 0x200; + } + + /* Update FIFO access slot counter */ + fifo_slots += (slots << fifo_byte_access); + } + + /* next FIFO update cycle */ + fifo_cycles = mcycles_vdp + fifo_timing[count | fifo_byte_access]; } @@ -2252,9 +2283,11 @@ static void vdp_68k_data_w_m4(unsigned int data) } else { - /* CPU is halted until last FIFO entry has been processed (Chaos Engine, Soldiers of Fortune, Double Clutch) */ - fifo_lastwrite += fifo_latency; - m68k.cycles = fifo_lastwrite; + /* CPU is halted until next FIFO entry processing */ + m68k.cycles = fifo_cycles; + + /* Update FIFO access slot counter */ + fifo_slots = fifo_slots + 1 + fifo_byte_access; } } @@ -2342,9 +2375,11 @@ static void vdp_68k_data_w_m5(unsigned int data) } else { - /* CPU is halted until last FIFO entry has been processed (Chaos Engine, Soldiers of Fortune, Double Clutch) */ - fifo_lastwrite += fifo_latency; - m68k.cycles = fifo_lastwrite; + /* CPU is halted until next FIFO entry processing (Chaos Engine / Soldiers of Fortune, Double Clutch, Titan Overdrive Demo) */ + m68k.cycles = fifo_cycles; + + /* Update FIFO access slot counter */ + fifo_slots += (1 + fifo_byte_access); } } diff --git a/core/vdp_ctrl.h b/core/vdp_ctrl.h index 082c74c..14e7857 100644 --- a/core/vdp_ctrl.h +++ b/core/vdp_ctrl.h @@ -75,7 +75,7 @@ extern uint16 vc_max; extern uint16 vscroll; extern uint16 lines_per_frame; extern int32 fifo_write_cnt; -extern uint32 fifo_lastwrite; +extern uint32 fifo_slots; extern uint32 hvc_latch; extern const uint8 *hctab; From 50d3603c17859d4e23b5070a58b0abe6066c19db Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 20 Oct 2013 20:53:33 +0200 Subject: [PATCH 17/39] [Core/VDP] improved Mode 5 sprites rendering (fixes "Overdrive" demo) --- core/system.c | 4 +- core/vdp_ctrl.c | 40 ++-- core/vdp_ctrl.h | 1 + core/vdp_render.c | 483 +++++++++++++++++++++++++--------------------- core/vdp_render.h | 41 ++-- 5 files changed, 318 insertions(+), 251 deletions(-) diff --git a/core/system.c b/core/system.c index 38bf293..b718bb2 100644 --- a/core/system.c +++ b/core/system.c @@ -1172,7 +1172,7 @@ void system_frame_sms(int do_skip) /* Sprites are still processed during vertical borders */ if (reg[1] & 0x40) { - render_obj(bitmap.viewport.w); + render_obj(1); } } @@ -1349,7 +1349,7 @@ void system_frame_sms(int do_skip) if ((system_hw < SYSTEM_MD) && (line > (lines_per_frame - 16))) { /* Sprites are still processed during top border */ - render_obj(bitmap.viewport.w); + render_obj((line - lines_per_frame) & 1); parse_satb(line - lines_per_frame); } diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index 908997b..f8f2d67 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -85,6 +85,7 @@ uint8 vdp_pal; /* 1: PAL , 0: NTSC (default) */ uint16 v_counter; /* Vertical counter */ uint16 vc_max; /* Vertical counter overflow value */ uint16 lines_per_frame; /* PAL: 313 lines, NTSC: 262 lines */ +uint16 max_sprite_pixels; /* Max. sprites pixels per line (parsing & rendering) */ int32 fifo_write_cnt; /* VDP FIFO write count */ uint32 fifo_slots; /* VDP FIFO access slot count */ uint32 hvc_latch; /* latched HV counter */ @@ -278,6 +279,9 @@ void vdp_reset(void) bitmap.viewport.ow = 256; bitmap.viewport.oh = 192; + /* default sprite pixel width */ + max_sprite_pixels = 256; + /* default overscan area */ if ((system_hw == SYSTEM_GG) && !config.gg_extra) { @@ -1575,21 +1579,28 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) if ((r & 0x40) && (v_counter < bitmap.viewport.h)) { /* Cycle offset vs HBLANK */ - int offset = cycles - mcycles_vdp - 860; - if (offset <= 0) + int offset = cycles - mcycles_vdp; + if (offset <= 860) { - /* If display was disabled during HBLANK (Mickey Mania 3D level), sprite rendering is limited */ - if ((d & 0x40) && (object_count > 5) && (offset >= -500)) + /* Sprite rendering is limited if display was disabled during HBLANK (Mickey Mania 3d level, Overdrive Demo) */ + if (d & 0x40) { - object_count = 5; + /* NB: This is not 100% accurate. On real hardware, the maximal number of rendered sprites pixels */ + /* for the current line (normally 256 or 320 pixels) but also the maximal number of pre-processed */ + /* sprites for the next line (normally 64 or 80 sprites) are both reduced depending on the amount */ + /* of cycles spent with display disabled. Here we only reduce them by a fixed amount when display */ + /* has been reenabled after a specific point within HBLANK. */ + if (offset > 360) + { + max_sprite_pixels = 128; + } } /* Redraw entire line (Legend of Galahad, Lemmings 2, Formula One, Kawasaki Super Bike, Deadly Moves,...) */ render_line(v_counter); -#ifdef LOGVDP - error("Line redrawn (%d sprites) \n",object_count); -#endif + /* Restore default */ + max_sprite_pixels = 256 + ((reg[12] & 1) << 6); } else if (system_hw & SYSTEM_MD) { @@ -1597,20 +1608,17 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) if (reg[12] & 1) { /* dot clock = MCLK / 8 */ - offset = (offset / 8); + offset = ((offset - 860) / 8) + 16; } else { /* dot clock = MCLK / 10 */ - offset = (offset / 10) + 16; + offset = ((offset - 860) / 10) + 16; } /* Line is partially blanked (Nigel Mansell's World Championship Racing , Ren & Stimpy Show, ...) */ if (offset < bitmap.viewport.w) { -#ifdef LOGVDP - error("Line %d redrawn from pixel %d\n",v_counter,offset); -#endif if (d & 0x40) { render_line(v_counter); @@ -1974,6 +1982,9 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) /* Update clipping */ window_clip(reg[17], 1); + + /* Max. sprite pixels per line */ + max_sprite_pixels = 320; } else { @@ -1988,6 +1999,9 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) /* Update clipping */ window_clip(reg[17], 0); + + /* Max. sprite pixels per line */ + max_sprite_pixels = 256; } /* Active display width modified during HBLANK (Bugs Bunny Double Trouble) */ diff --git a/core/vdp_ctrl.h b/core/vdp_ctrl.h index 14e7857..b83c2f0 100644 --- a/core/vdp_ctrl.h +++ b/core/vdp_ctrl.h @@ -74,6 +74,7 @@ extern uint16 v_counter; extern uint16 vc_max; extern uint16 vscroll; extern uint16 lines_per_frame; +extern uint16 max_sprite_pixels; extern int32 fifo_write_cnt; extern uint32 fifo_slots; extern uint32 hvc_latch; diff --git a/core/vdp_render.c b/core/vdp_render.c index 2bf951f..c6a9072 100644 --- a/core/vdp_render.c +++ b/core/vdp_render.c @@ -572,24 +572,26 @@ static uint8 linebuf[2][0x200]; /* Sprite limit flag */ static uint8 spr_ovr; -/* Sprites parsing */ -static struct +/* Sprite parsing lists */ +typedef struct { uint16 ypos; uint16 xpos; uint16 attr; uint16 size; -} object_info[20]; +} object_info_t; + +static object_info_t obj_info[2][20]; /* Sprite Counter */ -uint8 object_count; +static uint8 object_count[2]; /* Sprite Collision Info */ uint16 spr_col; /* Function pointers */ -void (*render_bg)(int line, int width); -void (*render_obj)(int max_width); +void (*render_bg)(int line); +void (*render_obj)(int line); void (*parse_satb)(int line); void (*update_bg_pattern_cache)(int index); @@ -1022,7 +1024,7 @@ void color_update_m4(int index, unsigned int data) case SYSTEM_SG: { - /* Fixed TMS9918 palette */ + /* Fixed TMS99xx palette */ if (index & 0x0F) { /* Colors 1-15 */ @@ -1080,7 +1082,7 @@ void color_update_m4(int index, unsigned int data) } else { - /* TMS9918 modes (palette bit forced to 1 because Game Gear uses CRAM palette #1) */ + /* TMS99xx modes (palette bit forced to 1 because Game Gear uses CRAM palette #1) */ if ((index == 0x40) || (index == (0x10 | (reg[7] & 0x0F)))) { /* Update backdrop color */ @@ -1138,7 +1140,7 @@ void color_update_m5(int index, unsigned int data) /*--------------------------------------------------------------------------*/ /* Graphics I */ -void render_bg_m0(int line, int width) +void render_bg_m0(int line) { uint8 color, pattern; uint16 name; @@ -1149,7 +1151,7 @@ void render_bg_m0(int line, int width) uint8 *pg = &vram[((reg[4] << 11) & 0x3800) + (line & 7)]; /* 32 x 8 pixels */ - width = 32; + int width = 32; do { @@ -1170,7 +1172,7 @@ void render_bg_m0(int line, int width) } /* Text */ -void render_bg_m1(int line, int width) +void render_bg_m1(int line) { uint8 pattern; uint8 color = reg[7]; @@ -1179,13 +1181,13 @@ void render_bg_m1(int line, int width) uint8 *nt = &vram[((reg[2] << 10) & 0x3C00) + ((line >> 3) * 40)]; uint8 *pg = &vram[((reg[4] << 11) & 0x3800) + (line & 7)]; + /* 40 x 6 pixels */ + int width = 40; + /* Left border (8 pixels) */ memset (lb, 0x40, 8); lb += 8; - /* 40 x 6 pixels */ - width = 40; - do { pattern = pg[*nt++]; @@ -1204,7 +1206,7 @@ void render_bg_m1(int line, int width) } /* Text + extended PG */ -void render_bg_m1x(int line, int width) +void render_bg_m1x(int line) { uint8 pattern; uint8 *pg; @@ -1216,7 +1218,10 @@ void render_bg_m1x(int line, int width) uint16 pg_mask = ~0x3800 ^ (reg[4] << 11); - /* Unused bits used as a mask on TMS9918 & 315-5124 VDP only */ + /* 40 x 6 pixels */ + int width = 40; + + /* Unused bits used as a mask on TMS99xx & 315-5124 VDP only */ if (system_hw > SYSTEM_SMS) { pg_mask |= 0x1800; @@ -1228,9 +1233,6 @@ void render_bg_m1x(int line, int width) memset (lb, 0x40, 8); lb += 8; - /* 40 x 6 pixels */ - width = 40; - do { pattern = pg[*nt++ << 3]; @@ -1249,7 +1251,7 @@ void render_bg_m1x(int line, int width) } /* Graphics II */ -void render_bg_m2(int line, int width) +void render_bg_m2(int line) { uint8 color, pattern; uint16 name; @@ -1261,7 +1263,10 @@ void render_bg_m2(int line, int width) uint16 ct_mask = ~0x3FC0 ^ (reg[3] << 6); uint16 pg_mask = ~0x3800 ^ (reg[4] << 11); - /* Unused bits used as a mask on TMS9918 & 315-5124 VDP only */ + /* 32 x 8 pixels */ + int width = 32; + + /* Unused bits used as a mask on TMS99xx & 315-5124 VDP only */ if (system_hw > SYSTEM_SMS) { ct_mask |= 0x1FC0; @@ -1271,9 +1276,6 @@ void render_bg_m2(int line, int width) ct = &vram[((0x2000 + ((line & 0xC0) << 5)) & ct_mask) + (line & 7)]; pg = &vram[((0x2000 + ((line & 0xC0) << 5)) & pg_mask) + (line & 7)]; - /* 32 x 8 pixels */ - width = 32; - do { name = *nt++ << 3 ; @@ -1293,7 +1295,7 @@ void render_bg_m2(int line, int width) } /* Multicolor */ -void render_bg_m3(int line, int width) +void render_bg_m3(int line) { uint8 color; uint16 name; @@ -1303,7 +1305,7 @@ void render_bg_m3(int line, int width) uint8 *pg = &vram[((reg[4] << 11) & 0x3800) + ((line >> 2) & 7)]; /* 32 x 8 pixels */ - width = 32; + int width = 32; do { @@ -1323,7 +1325,7 @@ void render_bg_m3(int line, int width) } /* Multicolor + extended PG */ -void render_bg_m3x(int line, int width) +void render_bg_m3x(int line) { uint8 color; uint16 name; @@ -1334,7 +1336,10 @@ void render_bg_m3x(int line, int width) uint16 pg_mask = ~0x3800 ^ (reg[4] << 11); - /* Unused bits used as a mask on TMS9918 & 315-5124 VDP only */ + /* 32 x 8 pixels */ + int width = 32; + + /* Unused bits used as a mask on TMS99xx & 315-5124 VDP only */ if (system_hw > SYSTEM_SMS) { pg_mask |= 0x1800; @@ -1342,9 +1347,6 @@ void render_bg_m3x(int line, int width) pg = &vram[((0x2000 + ((line & 0xC0) << 5)) & pg_mask) + ((line >> 2) & 7)]; - /* 32 x 8 pixels */ - width = 32; - do { name = *nt++; @@ -1363,19 +1365,19 @@ void render_bg_m3x(int line, int width) } /* Invalid (2+3/1+2+3) */ -void render_bg_inv(int line, int width) +void render_bg_inv(int line) { uint8 color = reg[7]; uint8 *lb = &linebuf[0][0x20]; + /* 40 x 6 pixels */ + int width = 40; + /* Left border (8 pixels) */ memset (lb, 0x40, 8); lb += 8; - /* 40 x 6 pixels */ - width = 40; - do { *lb++ = 0x10 | ((color >> 4) & 0x0F); @@ -1392,12 +1394,15 @@ void render_bg_inv(int line, int width) } /* Mode 4 */ -void render_bg_m4(int line, int width) +void render_bg_m4(int line) { int column; uint16 *nt; uint32 attr, atex, *src; - + + /* 32 x 8 pixels */ + int width = 32; + /* Horizontal scrolling */ int index = ((reg[0] & 0x40) && (line < 0x10)) ? 0x100 : reg[0x08]; int shift = index & 7; @@ -1411,7 +1416,7 @@ void render_bg_m4(int line, int width) /* Pattern name table mask */ uint16 nt_mask = ~0x3C00 ^ (reg[2] << 10); - /* Unused bits used as a mask on TMS9918 & 315-5124 VDP only */ + /* Unused bits used as a mask on TMS99xx & 315-5124 VDP only */ if (system_hw > SYSTEM_SMS) { nt_mask |= 0x400; @@ -1448,9 +1453,6 @@ void render_bg_m4(int line, int width) index++; } - /* Number of tiles to draw */ - width >>= 3; - /* Draw tiles */ for(column = 0; column < width; column++, index++) { @@ -1498,14 +1500,14 @@ void render_bg_m4(int line, int width) /* Mode 5 */ #ifndef ALT_RENDERER -void render_bg_m5(int line, int width) +void render_bg_m5(int line) { int column; uint32 atex, atbuf, *src, *dst; /* Common data */ - uint32 xscroll = *(uint32 *)&vram[hscb + ((line & hscroll_mask) << 2)]; - uint32 yscroll = *(uint32 *)&vsram[0]; + uint32 xscroll = *(uint32 *)&vram[hscb + ((line & hscroll_mask) << 2)]; + uint32 yscroll = *(uint32 *)&vsram[0]; uint32 pf_col_mask = playfield_col_mask; uint32 pf_row_mask = playfield_row_mask; uint32 pf_shift = playfield_shift; @@ -1516,7 +1518,7 @@ void render_bg_m5(int line, int width) /* Plane B width */ int start = 0; - int end = width >> 4; + int end = bitmap.viewport.w >> 4; /* Plane B scroll */ #ifdef LSB_FIRST @@ -1644,9 +1646,12 @@ void render_bg_m5(int line, int width) DRAW_COLUMN(atbuf, v_line) } } + + /* Merge background layers */ + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[(reg[12] & 0x08) >> 2], bitmap.viewport.w); } -void render_bg_m5_vs(int line, int width) +void render_bg_m5_vs(int line) { int column; uint32 atex, atbuf, *src, *dst; @@ -1666,7 +1671,7 @@ void render_bg_m5_vs(int line, int width) /* Plane B width */ int start = 0; - int end = width >> 4; + int end = bitmap.viewport.w >> 4; /* Plane B horizontal scroll */ #ifdef LSB_FIRST @@ -1831,9 +1836,12 @@ void render_bg_m5_vs(int line, int width) DRAW_COLUMN(atbuf, v_line) } } + + /* Merge background layers */ + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[(reg[12] & 0x08) >> 2], bitmap.viewport.w); } -void render_bg_m5_im2(int line, int width) +void render_bg_m5_im2(int line) { int column; uint32 atex, atbuf, *src, *dst; @@ -1852,7 +1860,7 @@ void render_bg_m5_im2(int line, int width) /* Plane B width */ int start = 0; - int end = width >> 4; + int end = bitmap.viewport.w >> 4; /* Plane B scroll */ #ifdef LSB_FIRST @@ -1980,9 +1988,12 @@ void render_bg_m5_im2(int line, int width) DRAW_COLUMN_IM2(atbuf, v_line) } } + + /* Merge background layers */ + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[(reg[12] & 0x08) >> 2], bitmap.viewport.w); } -void render_bg_m5_im2_vs(int line, int width) +void render_bg_m5_im2_vs(int line) { int column; uint32 atex, atbuf, *src, *dst; @@ -2003,7 +2014,7 @@ void render_bg_m5_im2_vs(int line, int width) /* Plane B width */ int start = 0; - int end = width >> 4; + int end = bitmap.viewport.w >> 4; /* Plane B horizontal scroll */ #ifdef LSB_FIRST @@ -2168,11 +2179,14 @@ void render_bg_m5_im2_vs(int line, int width) DRAW_COLUMN_IM2(atbuf, v_line) } } + + /* Merge background layers */ + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[(reg[12] & 0x08) >> 2], bitmap.viewport.w); } #else -void render_bg_m5(int line, int width) +void render_bg_m5(int line) { int column, start, end; uint32 atex, atbuf, *src, *dst; @@ -2186,6 +2200,9 @@ void render_bg_m5(int line, int width) uint32 pf_row_mask = playfield_row_mask; uint32 pf_shift = playfield_shift; + /* Number of columns to draw */ + int width = bitmap.viewport.w >> 4; + /* Layer priority table */ uint8 *table = lut[(reg[12] & 8) >> 2]; @@ -2209,9 +2226,6 @@ void render_bg_m5(int line, int width) w = clip[1].enable; } - /* Number of columns to draw */ - width >>= 4; - /* Plane A */ if (a) { @@ -2329,7 +2343,7 @@ void render_bg_m5(int line, int width) } } -void render_bg_m5_vs(int line, int width) +void render_bg_m5_vs(int line) { int column, start, end; uint32 atex, atbuf, *src, *dst; @@ -2344,6 +2358,9 @@ void render_bg_m5_vs(int line, int width) uint32 pf_shift = playfield_shift; uint32 *vs = (uint32 *)&vsram[0]; + /* Number of columns to draw */ + int width = bitmap.viewport.w >> 4; + /* Layer priority table */ uint8 *table = lut[(reg[12] & 8) >> 2]; @@ -2375,9 +2392,6 @@ void render_bg_m5_vs(int line, int width) yscroll = vs[19] & (vs[19] >> 16); } - /* Number of columns to draw */ - width >>= 4; - /* Plane A*/ if (a) { @@ -2523,7 +2537,7 @@ void render_bg_m5_vs(int line, int width) } } -void render_bg_m5_im2(int line, int width) +void render_bg_m5_im2(int line) { int column, start, end; uint32 atex, atbuf, *src, *dst; @@ -2538,6 +2552,9 @@ void render_bg_m5_im2(int line, int width) uint32 pf_row_mask = playfield_row_mask; uint32 pf_shift = playfield_shift; + /* Number of columns to draw */ + int width = bitmap.viewport.w >> 4; + /* Layer priority table */ uint8 *table = lut[(reg[12] & 8) >> 2]; @@ -2561,9 +2578,6 @@ void render_bg_m5_im2(int line, int width) w = clip[1].enable; } - /* Number of columns to draw */ - width >>= 4; - /* Plane A */ if (a) { @@ -2681,7 +2695,7 @@ void render_bg_m5_im2(int line, int width) } } -void render_bg_m5_im2_vs(int line, int width) +void render_bg_m5_im2_vs(int line) { int column, start, end; uint32 atex, atbuf, *src, *dst; @@ -2697,6 +2711,9 @@ void render_bg_m5_im2_vs(int line, int width) uint32 pf_shift = playfield_shift; uint32 *vs = (uint32 *)&vsram[0]; + /* Number of columns to draw */ + int width = bitmap.viewport.w >> 4; + /* Layer priority table */ uint8 *table = lut[(reg[12] & 8) >> 2]; @@ -2729,9 +2746,6 @@ void render_bg_m5_im2_vs(int line, int width) yscroll = (vs[19] >> 1) & (vs[19] >> 17); } - /* Number of columns to draw */ - width >>= 4; - /* Plane A */ if (a) { @@ -2883,13 +2897,17 @@ void render_bg_m5_im2_vs(int line, int width) /* Sprite layer rendering functions */ /*--------------------------------------------------------------------------*/ -void render_obj_tms(int max_width) +void render_obj_tms(int line) { - int x, count, start, end; + int x, start, end; uint8 *lb, *sg; uint8 color, pattern[2]; uint16 temp; + /* Sprite list for current line */ + object_info_t *object_info = obj_info[line]; + int count = object_count[line]; + /* Default sprite width (8 pixels) */ int width = 8; @@ -2899,18 +2917,20 @@ void render_obj_tms(int max_width) /* Adjust width for zoomed sprites */ width <<= (reg[1] & 0x01); - /* Set SOVR flag */ + /* Latch SOVR flag from previous line to VDP status */ status |= spr_ovr; + + /* Clear SOVR flag for current line */ spr_ovr = 0; /* Draw sprites in front-to-back order */ - for (count = 0; count < object_count; count++) + while (count--) { /* Sprite X position */ - start = object_info[count].xpos; + start = object_info->xpos; /* Sprite Color + Early Clock bit */ - color = object_info[count].size; + color = object_info->size; /* X position shift (32 pixels) */ start -= ((color & 0x80) >> 2); @@ -2922,7 +2942,6 @@ void render_obj_tms(int max_width) { /* Clip sprites on right edge */ end = 256 - start; - start = 0; } else @@ -2944,14 +2963,14 @@ void render_obj_tms(int max_width) color &= 0x0F; /* Sprite Pattern Name */ - temp = object_info[count].attr; + temp = object_info->attr; /* Mask two LSB for 16x16 sprites */ temp &= ~((reg[1] & 0x02) >> 0); temp &= ~((reg[1] & 0x02) >> 1); /* Pointer to sprite generator table */ - sg = (uint8 *)&vram[((reg[6] << 11) & 0x3800) | (temp << 3) | object_info[count].ypos]; + sg = (uint8 *)&vram[((reg[6] << 11) & 0x3800) | (temp << 3) | object_info->ypos]; /* Sprite Pattern data (2 x 8 pixels) */ pattern[0] = sg[0x00]; @@ -2987,6 +3006,9 @@ void render_obj_tms(int max_width) status |= ((temp & 0x8000) >> 10); } } + + /* Next sprite entry */ + object_info++; } /* handle Game Gear reduced screen (160x144) */ @@ -2995,7 +3017,7 @@ void render_obj_tms(int max_width) int line = v_counter - (bitmap.viewport.h - 144) / 2; if ((line < 0) || (line >= 144)) { - memset(&linebuf[0][0x20], 0x40, max_width); + memset(&linebuf[0][0x20], 0x40, 256); } else { @@ -3008,12 +3030,16 @@ void render_obj_tms(int max_width) } } -void render_obj_m4(int max_width) +void render_obj_m4(int line) { - int i, count, xpos, end; + int i, xpos, end; uint8 *src, *lb; uint16 temp; + /* Sprite list for current line */ + object_info_t *object_info = obj_info[line]; + int count = object_count[line]; + /* Default sprite width */ int width = 8; @@ -3032,31 +3058,23 @@ void render_obj_m4(int max_width) sg_mask |= 0xC0; } - /* Set SOVR flag */ + /* Latch SOVR flag from previous line to VDP status */ status |= spr_ovr; + + /* Clear SOVR flag for current line */ spr_ovr = 0; /* Draw sprites in front-to-back order */ - for (count = 0; count < object_count; count++) + while (count--) { - /* 315-5124 VDP specific */ - if (count == 4) - { - if (system_hw < SYSTEM_SMS2) - { - /* Only 4 first sprites can be zoomed */ - width = 8; - } - } - /* Sprite pattern index */ - temp = (object_info[count].attr | 0x100) & sg_mask; + temp = (object_info->attr | 0x100) & sg_mask; /* Pointer to pattern cache line */ - src = (uint8 *)&bg_pattern_cache[(temp << 6) | (object_info[count].ypos << 3)]; + src = (uint8 *)&bg_pattern_cache[(temp << 6) | (object_info->ypos << 3)]; /* Sprite X position */ - xpos = object_info[count].xpos; + xpos = object_info->xpos; /* X position shift */ xpos -= (reg[0] & 0x08); @@ -3068,10 +3086,10 @@ void render_obj_m4(int max_width) end = xpos + width; xpos = 0; } - else if ((xpos + width) > max_width) + else if ((xpos + width) > 256) { /* Clip sprites on right edge */ - end = max_width - xpos; + end = 256 - xpos; } else { @@ -3086,12 +3104,26 @@ void render_obj_m4(int max_width) { /* Draw sprite pattern (zoomed sprites are rendered at half speed) */ DRAW_SPRITE_TILE_ACCURATE_2X(end,0,lut[5]) + + /* 315-5124 VDP specific */ + if (system_hw < SYSTEM_SMS2) + { + /* only 4 first sprites can be zoomed */ + if (count == (object_count[line] - 4)) + { + /* Set default width for remaining sprites */ + width = 8; + } + } } else { /* Draw sprite pattern */ DRAW_SPRITE_TILE_ACCURATE(end,0,lut[5]) } + + /* Next sprite entry */ + object_info++; } /* handle Game Gear reduced screen (160x144) */ @@ -3100,7 +3132,7 @@ void render_obj_m4(int max_width) int line = v_counter - (bitmap.viewport.h - 144) / 2; if ((line < 0) || (line >= 144)) { - memset(&linebuf[0][0x20], 0x40, max_width); + memset(&linebuf[0][0x20], 0x40, 256); } else { @@ -3113,9 +3145,9 @@ void render_obj_m4(int max_width) } } -void render_obj_m5(int max_width) +void render_obj_m5(int line) { - int i, count, column; + int i, column; int xpos, width; int pixelcount = 0; int masked = 0; @@ -3124,16 +3156,15 @@ void render_obj_m5(int max_width) uint32 temp, v_line; uint32 attr, name, atex; -#ifndef ALT_RENDERER - /* Merge background layers */ - merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[0], max_width); -#endif + /* Sprite list for current line */ + object_info_t *object_info = obj_info[line]; + int count = object_count[line]; /* Draw sprites in front-to-back order */ - for (count = 0; count < object_count; count++) + while (count--) { /* Sprite X position */ - xpos = object_info[count].xpos; + xpos = object_info->xpos; /* Sprite masking */ if (xpos) @@ -3151,7 +3182,7 @@ void render_obj_m5(int max_width) xpos = xpos - 0x80; /* Sprite size */ - temp = object_info[count].size; + temp = object_info->size; /* Sprite width */ width = 8 + ((temp & 0x0C) << 1); @@ -3160,13 +3191,13 @@ void render_obj_m5(int max_width) pixelcount += width; /* Is sprite across visible area ? */ - if (((xpos + width) > 0) && (xpos < max_width) && !masked) + if (((xpos + width) > 0) && (xpos < bitmap.viewport.w) && !masked) { /* Sprite attributes */ - attr = object_info[count].attr; + attr = object_info->attr; /* Sprite vertical offset */ - v_line = object_info[count].ypos; + v_line = object_info->ypos; /* Sprite priority + palette bits */ atex = (attr >> 9) & 0x70; @@ -3183,10 +3214,11 @@ void render_obj_m5(int max_width) /* Pointer into line buffer */ lb = &linebuf[0][0x20 + xpos]; - /* Adjust number of pixels to draw for sprite limit */ - if (pixelcount > max_width) + /* Max. number of sprite pixels rendered per line */ + if (pixelcount > max_sprite_pixels) { - width = width - pixelcount + max_width; + /* Adjust number of pixels to draw */ + width -= (pixelcount - max_sprite_pixels); } /* Number of tiles to draw */ @@ -3196,7 +3228,7 @@ void render_obj_m5(int max_width) v_line = (v_line & 7) << 3; /* Draw sprite patterns */ - for(column = 0; column < width; column++, lb+=8) + for (column = 0; column < width; column++, lb+=8) { temp = attr | ((name + s[column]) & 0x07FF); src = &bg_pattern_cache[(temp << 6) | (v_line)]; @@ -3205,23 +3237,26 @@ void render_obj_m5(int max_width) } /* Sprite limit */ - if (pixelcount >= max_width) + if (pixelcount >= max_sprite_pixels) { - /* Sprite masking will be effective on next line */ - spr_ovr = 1; + /* Sprite masking is effective on next line if max pixel width is reached */ + spr_ovr = (pixelcount >= bitmap.viewport.w); /* Stop sprite rendering */ return; } + + /* Next sprite entry */ + object_info++; } /* Clear sprite masking for next line */ spr_ovr = 0; } -void render_obj_m5_ste(int max_width) +void render_obj_m5_ste(int line) { - int i, count, column; + int i, column; int xpos, width; int pixelcount = 0; int masked = 0; @@ -3230,19 +3265,18 @@ void render_obj_m5_ste(int max_width) uint32 temp, v_line; uint32 attr, name, atex; -#ifndef ALT_RENDERER - /* Merge background layers */ - merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[2], max_width); -#endif + /* Sprite list for current line */ + object_info_t *object_info = obj_info[line]; + int count = object_count[line]; /* Clear sprite line buffer */ - memset(&linebuf[1][0], 0, max_width + 0x40); + memset(&linebuf[1][0], 0, bitmap.viewport.w + 0x40); /* Draw sprites in front-to-back order */ - for (count = 0; count < object_count; count++) + while (count--) { /* Sprite X position */ - xpos = object_info[count].xpos; + xpos = object_info->xpos; /* Sprite masking */ if (xpos) @@ -3260,7 +3294,7 @@ void render_obj_m5_ste(int max_width) xpos = xpos - 0x80; /* Sprite size */ - temp = object_info[count].size; + temp = object_info->size; /* Sprite width */ width = 8 + ((temp & 0x0C) << 1); @@ -3269,13 +3303,13 @@ void render_obj_m5_ste(int max_width) pixelcount += width; /* Is sprite across visible area ? */ - if (((xpos + width) > 0) && (xpos < max_width) && !masked) + if (((xpos + width) > 0) && (xpos < bitmap.viewport.w) && !masked) { /* Sprite attributes */ - attr = object_info[count].attr; + attr = object_info->attr; /* Sprite vertical offset */ - v_line = object_info[count].ypos; + v_line = object_info->ypos; /* Sprite priority + palette bits */ atex = (attr >> 9) & 0x70; @@ -3293,9 +3327,9 @@ void render_obj_m5_ste(int max_width) lb = &linebuf[1][0x20 + xpos]; /* Adjust number of pixels to draw for sprite limit */ - if (pixelcount > max_width) + if (pixelcount > max_sprite_pixels) { - width = width - pixelcount + max_width; + width -= (pixelcount - max_sprite_pixels); } /* Number of tiles to draw */ @@ -3305,7 +3339,7 @@ void render_obj_m5_ste(int max_width) v_line = (v_line & 7) << 3; /* Draw sprite patterns */ - for(column = 0; column < width; column++, lb+=8) + for (column = 0; column < width; column++, lb+=8) { temp = attr | ((name + s[column]) & 0x07FF); src = &bg_pattern_cache[(temp << 6) | (v_line)]; @@ -3314,29 +3348,32 @@ void render_obj_m5_ste(int max_width) } /* Sprite limit */ - if (pixelcount >= max_width) + if (pixelcount >= max_sprite_pixels) { - /* Sprite masking will be effective on next line */ - spr_ovr = 1; + /* Sprite masking is effective on next line if max pixel width is reached */ + spr_ovr = (pixelcount >= bitmap.viewport.w); /* Merge background & sprite layers */ - merge(&linebuf[1][0x20],&linebuf[0][0x20],&linebuf[0][0x20],lut[4], max_width); + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[4], bitmap.viewport.w); /* Stop sprite rendering */ return; } + + /* Next sprite entry */ + object_info++; } /* Clear sprite masking for next line */ spr_ovr = 0; /* Merge background & sprite layers */ - merge(&linebuf[1][0x20],&linebuf[0][0x20],&linebuf[0][0x20],lut[4], max_width); + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[4], bitmap.viewport.w); } -void render_obj_m5_im2(int max_width) +void render_obj_m5_im2(int line) { - int i, count, column; + int i, column; int xpos, width; int pixelcount = 0; int masked = 0; @@ -3346,16 +3383,15 @@ void render_obj_m5_im2(int max_width) uint32 temp, v_line; uint32 attr, name, atex; -#ifndef ALT_RENDERER - /* Merge background layers */ - merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[0], max_width); -#endif + /* Sprite list for current line */ + object_info_t *object_info = obj_info[line]; + int count = object_count[line]; /* Draw sprites in front-to-back order */ - for (count = 0; count < object_count; count++) + while (count--) { /* Sprite X position */ - xpos = object_info[count].xpos; + xpos = object_info->xpos; /* Sprite masking */ if (xpos) @@ -3373,7 +3409,7 @@ void render_obj_m5_im2(int max_width) xpos = xpos - 0x80; /* Sprite size */ - temp = object_info[count].size; + temp = object_info->size; /* Sprite width */ width = 8 + ((temp & 0x0C) << 1); @@ -3382,13 +3418,13 @@ void render_obj_m5_im2(int max_width) pixelcount += width; /* Is sprite across visible area ? */ - if (((xpos + width) > 0) && (xpos < max_width) && !masked) + if (((xpos + width) > 0) && (xpos < bitmap.viewport.w) && !masked) { /* Sprite attributes */ - attr = object_info[count].attr; + attr = object_info->attr; /* Sprite y offset */ - v_line = object_info[count].ypos; + v_line = object_info->ypos; /* Sprite priority + palette bits */ atex = (attr >> 9) & 0x70; @@ -3406,9 +3442,9 @@ void render_obj_m5_im2(int max_width) lb = &linebuf[0][0x20 + xpos]; /* Adjust width for sprite limit */ - if (pixelcount > max_width) + if (pixelcount > max_sprite_pixels) { - width = width - pixelcount + max_width; + width -= (pixelcount - max_sprite_pixels); } /* Number of tiles to draw */ @@ -3427,23 +3463,26 @@ void render_obj_m5_im2(int max_width) } /* Sprite Limit */ - if (pixelcount >= max_width) + if (pixelcount >= max_sprite_pixels) { - /* Enable sprite masking for next line */ - spr_ovr = 1; + /* Sprite masking is effective on next line if max pixel width is reached */ + spr_ovr = (pixelcount >= bitmap.viewport.w); /* Stop sprite rendering */ return; } + + /* Next sprite entry */ + object_info++; } /* Clear sprite masking for next line */ spr_ovr = 0; } -void render_obj_m5_im2_ste(int max_width) +void render_obj_m5_im2_ste(int line) { - int i, count, column; + int i, column; int xpos, width; int pixelcount = 0; int masked = 0; @@ -3453,19 +3492,18 @@ void render_obj_m5_im2_ste(int max_width) uint32 temp, v_line; uint32 attr, name, atex; -#ifndef ALT_RENDERER - /* Merge background layers */ - merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[2], max_width); -#endif + /* Sprite list for current line */ + object_info_t *object_info = obj_info[line]; + int count = object_count[line]; /* Clear sprite line buffer */ - memset(&linebuf[1][0], 0, max_width + 0x40); + memset(&linebuf[1][0], 0, bitmap.viewport.w + 0x40); /* Draw sprites in front-to-back order */ - for (count = 0; count < object_count; count++) + while (count--) { /* Sprite X position */ - xpos = object_info[count].xpos; + xpos = object_info->xpos; /* Sprite masking */ if (xpos) @@ -3483,7 +3521,7 @@ void render_obj_m5_im2_ste(int max_width) xpos = xpos - 0x80; /* Sprite size */ - temp = object_info[count].size; + temp = object_info->size; /* Sprite width */ width = 8 + ((temp & 0x0C) << 1); @@ -3492,13 +3530,13 @@ void render_obj_m5_im2_ste(int max_width) pixelcount += width; /* Is sprite across visible area ? */ - if (((xpos + width) > 0) && (xpos < max_width) && !masked) + if (((xpos + width) > 0) && (xpos < bitmap.viewport.w) && !masked) { /* Sprite attributes */ - attr = object_info[count].attr; + attr = object_info->attr; /* Sprite y offset */ - v_line = object_info[count].ypos; + v_line = object_info->ypos; /* Sprite priority + palette bits */ atex = (attr >> 9) & 0x70; @@ -3516,9 +3554,9 @@ void render_obj_m5_im2_ste(int max_width) lb = &linebuf[1][0x20 + xpos]; /* Adjust width for sprite limit */ - if (pixelcount > max_width) + if (pixelcount > max_sprite_pixels) { - width = width - pixelcount + max_width; + width -= (pixelcount - max_sprite_pixels); } /* Number of tiles to draw */ @@ -3537,24 +3575,27 @@ void render_obj_m5_im2_ste(int max_width) } /* Sprite Limit */ - if (pixelcount >= max_width) + if (pixelcount >= max_sprite_pixels) { - /* Enable sprite masking for next line */ - spr_ovr = 1; + /* Sprite masking is effective on next line if max pixel width is reached */ + spr_ovr = (pixelcount >= bitmap.viewport.w); /* Merge background & sprite layers */ - merge(&linebuf[1][0x20],&linebuf[0][0x20],&linebuf[0][0x20],lut[4], max_width); + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[4], bitmap.viewport.w); /* Stop sprite rendering */ return; } + + /* Next sprite entry */ + object_info++; } /* Clear sprite masking for next line */ spr_ovr = 0; /* Merge background & sprite layers */ - merge(&linebuf[1][0x20],&linebuf[0][0x20],&linebuf[0][0x20],lut[4], max_width); + merge(&linebuf[1][0x20], &linebuf[0][0x20], &linebuf[0][0x20], lut[4], bitmap.viewport.w); } @@ -3572,12 +3613,15 @@ void parse_satb_tms(int line) /* no sprites in Text modes */ if (!(reg[1] & 0x10)) { - /* Pointer to sprite attribute table */ - uint8 *st = &vram[(reg[5] << 7) & 0x3F80]; - /* Y position */ int ypos; + /* Sprite list for next line */ + object_info_t *object_info = obj_info[(line + 1) & 1]; + + /* Pointer to sprite attribute table */ + uint8 *st = &vram[(reg[5] << 7) & 0x3F80]; + /* Sprite height (8 pixels by default) */ int height = 8; @@ -3608,7 +3652,7 @@ void parse_satb_tms(int line) /* Y range */ ypos = line - ypos; - /* Sprite is visble on this line ? */ + /* Sprite is visible on this line ? */ if ((ypos >= 0) && (ypos < height)) { /* Sprite overflow */ @@ -3626,20 +3670,23 @@ void parse_satb_tms(int line) ypos >>= (reg[1] & 0x01); /* Store sprite attributes for later processing */ - object_info[count].ypos = ypos; - object_info[count].xpos = st[(i << 2) + 1]; - object_info[count].attr = st[(i << 2) + 2]; - object_info[count].size = st[(i << 2) + 3]; + object_info->ypos = ypos; + object_info->xpos = st[(i << 2) + 1]; + object_info->attr = st[(i << 2) + 2]; + object_info->size = st[(i << 2) + 3]; /* Increment Sprite count */ ++count; + + /* Next sprite entry */ + object_info++; } } while (++i < 32); } /* Update sprite count for next line */ - object_count = count; + object_count[(line + 1) & 1] = count; /* Insert number of last sprite entry processed */ status = (status & 0xE0) | (i & 0x1F); @@ -3655,6 +3702,9 @@ void parse_satb_m4(int line) /* Y position */ int ypos; + + /* Sprite list for next line */ + object_info_t *object_info = obj_info[(line + 1) & 1]; /* Sprite height (8x8 or 8x16) */ int height = 8 + ((reg[1] & 0x02) << 2); @@ -3713,18 +3763,21 @@ void parse_satb_m4(int line) } /* Store sprite attributes for later processing */ - object_info[count].ypos = ypos; - object_info[count].xpos = st[(0x80 + (i << 1)) & st_mask]; - object_info[count].attr = st[(0x81 + (i << 1)) & st_mask]; + object_info->ypos = ypos; + object_info->xpos = st[(0x80 + (i << 1)) & st_mask]; + object_info->attr = st[(0x81 + (i << 1)) & st_mask]; /* Increment Sprite count */ ++count; + + /* Next sprite entry */ + object_info++; } } while (++i < 64); /* Update sprite count for next line */ - object_count = count; + object_count[(line + 1) & 1] = count; } void parse_satb_m5(int line) @@ -3744,11 +3797,11 @@ void parse_satb_m5(int line) /* Sprite counter */ int count = 0; - /* 16 or 20 sprites max. per line */ - int max = 16 + ((reg[12] & 1) << 2); + /* max. number of rendered sprites (16 or 20 sprites per line by default) */ + int max = bitmap.viewport.w >> 4; - /* 64 or 80 sprites max. */ - int total = max << 2; + /* max. number of parsed sprites (64 or 80 sprites per line by default) */ + int total = max_sprite_pixels >> 2; /* Pointer to sprite attribute table */ uint16 *p = (uint16 *) &vram[satb]; @@ -3756,6 +3809,9 @@ void parse_satb_m5(int line) /* Pointer to internal RAM */ uint16 *q = (uint16 *) &sat[0]; + /* Sprite list for next line */ + object_info_t *object_info = obj_info[(line + 1) & 1]; + /* Adjust line offset */ line += 0x81; @@ -3781,13 +3837,17 @@ void parse_satb_m5(int line) break; } - /* Update sprite list */ - /* name, attribute & xpos are parsed from VRAM */ - object_info[count].attr = p[link + 2]; - object_info[count].xpos = p[link + 3] & 0x1ff; - object_info[count].ypos = ypos; - object_info[count].size = size & 0x0f; + /* Update sprite list (only name, attribute & xpos are parsed from VRAM) */ + object_info->attr = p[link + 2]; + object_info->xpos = p[link + 3] & 0x1ff; + object_info->ypos = ypos; + object_info->size = size & 0x0f; + + /* Increment Sprite count */ ++count; + + /* Next sprite entry */ + object_info++; } /* Read link data from internal SAT */ @@ -3798,8 +3858,8 @@ void parse_satb_m5(int line) } while (--total); - /* Update sprite count for next line */ - object_count = count; + /* Update sprite count for next line (line value already incremented) */ + object_count[line & 1] = count; } @@ -4020,7 +4080,7 @@ void render_reset(void) memset ((char *) bg_pattern_cache, 0, sizeof (bg_pattern_cache)); /* Reset Sprite infos */ - spr_ovr = spr_col = object_count = 0; + spr_ovr = spr_col = object_count[0] = object_count[1] = 0; } @@ -4030,9 +4090,6 @@ void render_reset(void) void render_line(int line) { - int width = bitmap.viewport.w; - int x_offset; - /* Check display status */ if (reg[1] & 0x40) { @@ -4044,10 +4101,10 @@ void render_line(int line) } /* Render BG layer(s) */ - render_bg(line, width); + render_bg(line); /* Render sprite layer */ - render_obj(width); + render_obj(line & 1); /* Left-most column blanking */ if (reg[0] & 0x20) @@ -4063,6 +4120,10 @@ void render_line(int line) { parse_satb(line); } + + /* Horizontal borders */ + memset(&linebuf[0][0x20 - bitmap.viewport.x], 0x40, bitmap.viewport.x); + memset(&linebuf[0][0x20 + bitmap.viewport.w], 0x40, bitmap.viewport.x); } else { @@ -4078,15 +4139,7 @@ void render_line(int line) } /* Blanked line */ - memset(&linebuf[0][0x20], 0x40, width); - } - - /* Horizontal borders */ - x_offset = bitmap.viewport.x; - if (x_offset > 0) - { - memset(&linebuf[0][0x20 - x_offset], 0x40, x_offset); - memset(&linebuf[0][0x20 + width], 0x40, x_offset); + memset(&linebuf[0][0x20 - bitmap.viewport.x], 0x40, bitmap.viewport.w + 2*bitmap.viewport.x); } /* Pixel color remapping */ @@ -4102,7 +4155,7 @@ void blank_line(int line, int offset, int width) void remap_line(int line) { /* Line width */ - int width = bitmap.viewport.w + (bitmap.viewport.x * 2); + int width = bitmap.viewport.w + 2*bitmap.viewport.x; /* Pixel line buffer */ uint8 *src = &linebuf[0][0x20 - bitmap.viewport.x]; diff --git a/core/vdp_render.h b/core/vdp_render.h index 4d40ffc..9ce924c 100644 --- a/core/vdp_render.h +++ b/core/vdp_render.h @@ -43,7 +43,6 @@ #define _RENDER_H_ /* Global variables */ -extern uint8 object_count; extern uint16 spr_col; /* Function prototypes */ @@ -53,24 +52,24 @@ extern void render_line(int line); extern void blank_line(int line, int offset, int width); extern void remap_line(int line); extern void window_clip(unsigned int data, unsigned int sw); -extern void render_bg_m0(int line, int width); -extern void render_bg_m1(int line, int width); -extern void render_bg_m1x(int line, int width); -extern void render_bg_m2(int line, int width); -extern void render_bg_m3(int line, int width); -extern void render_bg_m3x(int line, int width); -extern void render_bg_inv(int line, int width); -extern void render_bg_m4(int line, int width); -extern void render_bg_m5(int line, int width); -extern void render_bg_m5_vs(int line, int width); -extern void render_bg_m5_im2(int line, int width); -extern void render_bg_m5_im2_vs(int line, int width); -extern void render_obj_tms(int max_width); -extern void render_obj_m4(int max_width); -extern void render_obj_m5(int max_width); -extern void render_obj_m5_ste(int max_width); -extern void render_obj_m5_im2(int max_width); -extern void render_obj_m5_im2_ste(int max_width); +extern void render_bg_m0(int line); +extern void render_bg_m1(int line); +extern void render_bg_m1x(int line); +extern void render_bg_m2(int line); +extern void render_bg_m3(int line); +extern void render_bg_m3x(int line); +extern void render_bg_inv(int line); +extern void render_bg_m4(int line); +extern void render_bg_m5(int line); +extern void render_bg_m5_vs(int line); +extern void render_bg_m5_im2(int line); +extern void render_bg_m5_im2_vs(int line); +extern void render_obj_tms(int line); +extern void render_obj_m4(int line); +extern void render_obj_m5(int line); +extern void render_obj_m5_ste(int line); +extern void render_obj_m5_im2(int line); +extern void render_obj_m5_im2_ste(int line); extern void parse_satb_tms(int line); extern void parse_satb_m4(int line); extern void parse_satb_m5(int line); @@ -80,8 +79,8 @@ extern void color_update_m4(int index, unsigned int data); extern void color_update_m5(int index, unsigned int data); /* Function pointers */ -extern void (*render_bg)(int line, int width); -extern void (*render_obj)(int max_width); +extern void (*render_bg)(int line); +extern void (*render_obj)(int line); extern void (*parse_satb)(int line); extern void (*update_bg_pattern_cache)(int index); From 1b0db486e73c08adbbe8b2cb193978f447f2cafc Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 20 Oct 2013 23:40:00 +0200 Subject: [PATCH 18/39] [Core/VDP] fixed V28/V30 mode switching during active display (verified on real hardware) --- core/system.c | 16 ++++++++++++++-- core/vdp_ctrl.c | 13 ++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/system.c b/core/system.c index b718bb2..53a730b 100644 --- a/core/system.c +++ b/core/system.c @@ -404,11 +404,23 @@ void system_frame_gen(int do_skip) /* active screen height */ if (reg[1] & 0x04) { - bitmap.viewport.h = 224 + ((reg[1] & 0x08) << 1); - bitmap.viewport.y = (config.overscan & 1) * ((240 + 48*vdp_pal - bitmap.viewport.h) >> 1); + /* Mode 5 */ + if (reg[1] & 0x08) + { + /* 240 active lines */ + bitmap.viewport.h = 240; + bitmap.viewport.y = (config.overscan & 1) * 24 * vdp_pal; + } + else + { + /* 224 active lines */ + bitmap.viewport.h = 224; + bitmap.viewport.y = (config.overscan & 1) * (8 + (24 * vdp_pal)); + } } else { + /* Mode 4 (192 active lines) */ bitmap.viewport.h = 192; bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1); } diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index f8f2d67..0f2ed16 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -1659,17 +1659,8 @@ static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles) /* Mode 5 only */ if (d & 0x04) { - if (status & 8) - { - /* Changes should be applied on next frame */ - bitmap.viewport.changed |= 2; - } - else - { - /* Update active display height */ - bitmap.viewport.h = 224 + ((d & 8) << 1); - bitmap.viewport.y = (config.overscan & 1) * (8 - (d & 8) + 24*vdp_pal); - } + /* Changes should be applied on next frame */ + bitmap.viewport.changed |= 2; /* Update vertical counter max value */ vc_max = vc_table[(d >> 2) & 3][vdp_pal]; From 16b00f936830198b00568e5c14c2df82e34ebc4e Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 20 Oct 2013 23:48:36 +0200 Subject: [PATCH 19/39] [Core/VDP] implemented proper FIFO ring-buffer & unused bits behavior on CRAM/VSRAM reads (verified on real hardware) --- core/state.c | 4 +- core/vdp_ctrl.c | 121 ++++++++++++++++++++++++++++++++++-------------- core/vdp_ctrl.h | 2 +- 3 files changed, 90 insertions(+), 37 deletions(-) diff --git a/core/state.c b/core/state.c index e5b75f6..50b99c2 100644 --- a/core/state.c +++ b/core/state.c @@ -51,7 +51,7 @@ int state_load(unsigned char *state) return 0; } - /* version check (1.7.1 and above only) */ + /* version check (keep compatibility with previous & current state version) */ if ((version[11] < 0x31) || (version[13] < 0x37) || (version[15] < 0x31)) { return 0; @@ -110,7 +110,7 @@ int state_load(unsigned char *state) } /* VDP */ - bufferptr += vdp_context_load(&state[bufferptr]); + bufferptr += vdp_context_load(&state[bufferptr], version[15]); /* SOUND */ bufferptr += sound_context_load(&state[bufferptr]); diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index 0f2ed16..ce60d88 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -136,7 +136,8 @@ static uint16 dma_src; /* DMA source address */ static uint16 dmafill; /* DMA Fill setup */ static uint32 dma_endCycles; /* 68k cycles to DMA end */ static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */ -static uint16 fifo[4]; /* FIFO buffer */ +static uint16 fifo[4]; /* FIFO ring-buffer */ +static int fifo_idx; /* FIFO write index */ static int fifo_byte_access; /* FIFO byte access flag */ static uint32 fifo_cycles; /* FIFO next access cycle */ @@ -231,6 +232,7 @@ void vdp_reset(void) fifo_write_cnt = 0; fifo_cycles = 0; fifo_slots = 0; + fifo_idx = 0; cached_write = -1; fifo_byte_access = 1; @@ -312,16 +314,16 @@ void vdp_reset(void) parse_satb = parse_satb_m4; } - /* 68k bus access mode (Mode 4 by default) */ + /* default 68k bus interface (Mega Drive VDP only) */ vdp_68k_data_w = vdp_68k_data_w_m4; vdp_68k_data_r = vdp_68k_data_r_m4; - /* Z80 bus access mode */ + /* default Z80 bus interface */ switch (system_hw) { case SYSTEM_SG: { - /* SG-1000 port access */ + /* SG-1000 VDP (TMS99xx) */ vdp_z80_data_w = vdp_z80_data_w_sg; vdp_z80_data_r = vdp_z80_data_r_m4; break; @@ -329,7 +331,7 @@ void vdp_reset(void) case SYSTEM_GG: { - /* Game Gear port access */ + /* Game Gear VDP */ vdp_z80_data_w = vdp_z80_data_w_gg; vdp_z80_data_r = vdp_z80_data_r_m4; break; @@ -340,7 +342,7 @@ void vdp_reset(void) case SYSTEM_SMS2: case SYSTEM_GGMS: { - /* Master System port access */ + /* Master System or Game Gear (in MS compatibility mode) VDP */ vdp_z80_data_w = vdp_z80_data_w_ms; vdp_z80_data_r = vdp_z80_data_r_m4; break; @@ -348,7 +350,7 @@ void vdp_reset(void) default: { - /* Genesis port access */ + /* Mega Drive VDP (in MS compatibility mode) */ vdp_z80_data_w = vdp_z80_data_w_m4; vdp_z80_data_r = vdp_z80_data_r_m4; break; @@ -361,7 +363,7 @@ void vdp_reset(void) /* 16k address decoding by default (Magical Kid Wiz) */ vdp_reg_w(1, 0x80, 0); - /* no H-INT on TMS9918 */ + /* no H-INT on TMS99xx */ vdp_reg_w(10, 0xFF, 0); } @@ -418,6 +420,8 @@ int vdp_context_save(uint8 *state) save_param(&pending, sizeof(pending)); save_param(&status, sizeof(status)); save_param(&dmafill, sizeof(dmafill)); + save_param(&fifo_idx, sizeof(fifo_idx)); + save_param(&fifo, sizeof(fifo)); save_param(&hint_pending, sizeof(hint_pending)); save_param(&vint_pending, sizeof(vint_pending)); save_param(&dma_length, sizeof(dma_length)); @@ -427,7 +431,7 @@ int vdp_context_save(uint8 *state) return bufferptr; } -int vdp_context_load(uint8 *state) +int vdp_context_load(uint8 *state, uint8 version) { int i, bufferptr = 0; uint8 temp_reg[0x20]; @@ -473,13 +477,29 @@ int vdp_context_load(uint8 *state) load_param(&code, sizeof(code)); load_param(&pending, sizeof(pending)); load_param(&status, sizeof(status)); - load_param(&dmafill, sizeof(dmafill)); + + /* 1.7.1 state compatibility */ + if (version < 0x35) + { + uint16 temp; + load_param(&temp, 2); + dmafill = temp >> 8; + temp &= 0xff; + fifo_idx = 0; + fifo[0] = fifo[1] = fifo[2] = fifo[3] = (temp << 8) | temp; + } + else + { + load_param(&dmafill, sizeof(dmafill)); + load_param(&fifo_idx, sizeof(fifo_idx)); + load_param(&fifo, sizeof(fifo)); + } + load_param(&hint_pending, sizeof(hint_pending)); load_param(&vint_pending, sizeof(vint_pending)); load_param(&dma_length, sizeof(dma_length)); load_param(&dma_type, sizeof(dma_type)); load_param(&dma_src, sizeof(dma_src)); - load_param(&cached_write, sizeof(cached_write)); /* restore FIFO byte access flag */ @@ -528,7 +548,7 @@ int vdp_context_load(uint8 *state) /*--------------------------------------------------------------------------*/ -/* DMA update function */ +/* DMA update function (Mega Drive VDP only) */ /*--------------------------------------------------------------------------*/ void vdp_dma_update(unsigned int cycles) @@ -1097,7 +1117,7 @@ void vdp_sms_ctrl_w(unsigned int data) } } -/* TMS9918 (SG-1000) VDP control port specific */ +/* SG-1000 VDP (TMS99xx) control port specific */ void vdp_tms_ctrl_w(unsigned int data) { if(pending == 0) @@ -2140,7 +2160,13 @@ static void vdp_fifo_update(unsigned int cycles) static void vdp_bus_w(unsigned int data) { - /* Check destination code */ + /* write data to next FIFO entry */ + fifo[fifo_idx] = data; + + /* increment FIFO write pointer */ + fifo_idx = (fifo_idx + 1) & 3; + + /* Check destination code (CD0-CD3) */ switch (code & 0x0F) { case 0x01: /* VRAM */ @@ -2260,7 +2286,7 @@ static void vdp_bus_w(unsigned int data) /*--------------------------------------------------------------------------*/ -/* 68k data port access functions (Genesis mode) */ +/* 68k bus interface (Mega Drive VDP only) */ /*--------------------------------------------------------------------------*/ static void vdp_68k_data_w_m4(unsigned int data) @@ -2434,11 +2460,12 @@ static unsigned int vdp_68k_data_r_m5(void) /* Clear pending flag */ pending = 0; - switch (code & 0x0F) + /* Check destination code (CD0-CD3) & CD4 */ + switch (code & 0x1F) { - case 0x00: /* VRAM */ + case 0x00: { - /* Read data */ + /* read two bytes from VRAM */ data = *(uint16 *)&vram[addr & 0xFFFE]; #ifdef LOGVDP @@ -2447,10 +2474,23 @@ static unsigned int vdp_68k_data_r_m5(void) break; } - case 0x04: /* VSRAM */ + case 0x04: { - /* Read data */ - data = *(uint16 *)&vsram[addr & 0x7E]; + /* VSRAM index */ + int index = addr & 0x7E; + + /* Check against VSRAM max size (80 x 11-bits) */ + if (index >= 0x50) + { + /* Wrap to address 0 (TODO: check if still true with Genesis 3 model) */ + index = 0; + } + + /* Read 11-bit word from VSRAM */ + data = *(uint16 *)&vsram[index] & 0x7FF; + + /* Unused bits are set using data from next available FIFO entry */ + data |= (fifo[fifo_idx] & ~0x7FF); #ifdef LOGVDP error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); @@ -2458,24 +2498,30 @@ static unsigned int vdp_68k_data_r_m5(void) break; } - case 0x08: /* CRAM */ + case 0x08: { - /* Read data */ + /* Read 9-bit word from CRAM */ data = *(uint16 *)&cram[addr & 0x7E]; /* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit bus data (BBB0GGG0RRR0) */ data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1); + /* Unused bits are set using data from next available FIFO entry */ + data |= (fifo[fifo_idx] & ~0xEEE); + #ifdef LOGVDP error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); #endif break; } - case 0x0c: /* undocumented 8-bit VRAM read (cf. http://gendev.spritesmind.net/forum/viewtopic.php?t=790) */ + case 0x0c: /* undocumented 8-bit VRAM read */ { - /* Read data (MSB forced to zero) */ - data = *(uint16 *)&vram[addr & 0xFFFE] & 0xff; + /* Read one byte from VRAM adjacent address */ + data = READ_BYTE(vram, addr ^ 1); + + /* Unused bits are set using data from next available FIFO entry */ + data |= (fifo[fifo_idx] & ~0xFF); #ifdef LOGVDP error("[%d(%d)][%d(%d)] 8-bit VRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); @@ -2485,7 +2531,7 @@ static unsigned int vdp_68k_data_r_m5(void) default: { - /* Invalid code value */ + /* Invalid code value (normally locks VDP, hard reset required) */ #ifdef LOGERROR error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x read (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, m68k_get_reg(M68K_REG_PC)); #endif @@ -2502,7 +2548,7 @@ static unsigned int vdp_68k_data_r_m5(void) /*--------------------------------------------------------------------------*/ -/* Z80 data port access functions (Master System compatibility mode) */ +/* Z80 bus interface (Mega Drive VDP in Master System compatibility mode) */ /*--------------------------------------------------------------------------*/ static void vdp_z80_data_w_m4(unsigned int data) @@ -2562,7 +2608,11 @@ static void vdp_z80_data_w_m5(unsigned int data) /* Clear pending flag */ pending = 0; - /* Check destination code */ + /* Push byte into FIFO */ + fifo[fifo_idx] = data << 8; + fifo_idx = (fifo_idx + 1) & 3; + + /* Check destination code (CD0-CD3) */ switch (code & 0x0F) { case 0x01: /* VRAM */ @@ -2690,7 +2740,8 @@ static unsigned int vdp_z80_data_r_m5(void) /* Clear pending flag */ pending = 0; - switch (code & 0x0F) + /* Check destination code (CD0-CD3) & CD4 */ + switch (code & 0x1F) { case 0x00: /* VRAM */ { @@ -2734,7 +2785,7 @@ static unsigned int vdp_z80_data_r_m5(void) /*-----------------------------------------------------------------------------*/ -/* VDP specific data port access functions (Master System, Game Gear, SG-1000) */ +/* Z80 bus interface (Master System, Game Gear & SG-1000 VDP) */ /*-----------------------------------------------------------------------------*/ static void vdp_z80_data_w_ms(unsigned int data) @@ -2746,10 +2797,11 @@ static void vdp_z80_data_w_ms(unsigned int data) { int index; - /* check if we are already on next line */ + /* Check if we are already on next line */ int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame; if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special)) { + /* Render next line */ v_counter = line; render_line(line); } @@ -2813,10 +2865,11 @@ static void vdp_z80_data_w_gg(unsigned int data) { int index; - /* check if we are already on next line*/ + /* Check if we are already on next line*/ int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame; if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special)) { + /* Render next line */ v_counter = line; render_line(line); } @@ -2907,7 +2960,7 @@ static void vdp_z80_data_w_sg(unsigned int data) } /*--------------------------------------------------------------------------*/ -/* DMA operations */ +/* DMA operations (Mega Drive VDP only) */ /*--------------------------------------------------------------------------*/ /* DMA from 68K bus: $000000-$7FFFFF (external area) */ diff --git a/core/vdp_ctrl.h b/core/vdp_ctrl.h index b83c2f0..8a8ee8d 100644 --- a/core/vdp_ctrl.h +++ b/core/vdp_ctrl.h @@ -90,7 +90,7 @@ extern unsigned int (*vdp_z80_data_r)(void); extern void vdp_init(void); extern void vdp_reset(void); extern int vdp_context_save(uint8 *state); -extern int vdp_context_load(uint8 *state); +extern int vdp_context_load(uint8 *state, uint8 version); extern void vdp_dma_update(unsigned int cycles); extern void vdp_68k_ctrl_w(unsigned int data); extern void vdp_z80_ctrl_w(unsigned int data); From 71cf37cb14f132c9ddde727d84a4ee31984d5cdb Mon Sep 17 00:00:00 2001 From: EkeEke Date: Sun, 20 Oct 2013 23:58:15 +0200 Subject: [PATCH 20/39] [Core/VDP] improved accuracy of DMA Copy/Fill & added support for CRAM/VSRAM Fill (verified on real hardware) --- core/vdp_ctrl.c | 274 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 183 insertions(+), 91 deletions(-) diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index ce60d88..0b7b76a 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -133,8 +133,8 @@ static uint16 addr_latch; /* Latched A15, A14 of address */ static uint16 sat_base_mask; /* Base bits of SAT */ static uint16 sat_addr_mask; /* Index bits of SAT */ static uint16 dma_src; /* DMA source address */ -static uint16 dmafill; /* DMA Fill setup */ static uint32 dma_endCycles; /* 68k cycles to DMA end */ +static int dmafill; /* DMA Fill pending flag */ static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */ static uint16 fifo[4]; /* FIFO ring-buffer */ static int fifo_idx; /* FIFO write index */ @@ -649,7 +649,7 @@ void vdp_dma_update(unsigned int cycles) /* Check if DMA is finished */ if (!dma_length) { - /* DMA source address registers are incremented during DMA */ + /* DMA source address registers are incremented during DMA (even DMA Fill) */ uint16 end = reg[21] + (reg[22] << 8) + reg[19] + (reg[20] << 8); reg[21] = end & 0xff; reg[22] = end >> 8; @@ -730,17 +730,29 @@ void vdp_68k_ctrl_w(unsigned int data) { case 2: { - /* DMA Fill will be triggered by next DATA port write */ - dmafill = 0x100; + /* DMA Fill */ + dma_type = 2; + + /* DMA is pending until next DATA port write */ + dmafill = 1; + + /* Set DMA Busy flag */ + status |= 0x02; + + /* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */ + dma_endCycles = 0xffffffff; break; } case 3: { + /* DMA Copy */ + dma_type = 3; + /* DMA length */ dma_length = (reg[20] << 8) | reg[19]; - /* Zero DMA length */ + /* Zero DMA length (pre-decrementing counter) */ if (!dma_length) { dma_length = 0x10000; @@ -749,18 +761,20 @@ void vdp_68k_ctrl_w(unsigned int data) /* DMA source address */ dma_src = (reg[22] << 8) | reg[21]; - /* trigger DMA copy */ - dma_type = 3; + /* Trigger DMA */ vdp_dma_update(m68k.cycles); break; } default: { + /* DMA from 68k bus */ + dma_type = (code & 0x06) ? 0 : 1; + /* DMA length */ dma_length = (reg[20] << 8) | reg[19]; - /* Zero DMA length */ + /* Zero DMA length (pre-decrementing counter) */ if (!dma_length) { dma_length = 0x10000; @@ -779,8 +793,7 @@ void vdp_68k_ctrl_w(unsigned int data) dma_length--; } - /* trigger DMA from 68k bus */ - dma_type = (code & 0x06) ? 0 : 1; + /* Trigger DMA */ vdp_dma_update(m68k.cycles); break; } @@ -876,16 +889,25 @@ void vdp_z80_ctrl_w(unsigned int data) case 2: { /* DMA Fill will be triggered by next write to DATA port */ - dmafill = 0x100; + dmafill = 1; + + /* Set DMA Busy flag */ + status |= 0x02; + + /* DMA end cycle is not initialized yet (this prevents DMA Busy flag from being cleared on VDP status read) */ + dma_endCycles = 0xffffffff; break; } case 3: { + /* DMA copy */ + dma_type = 3; + /* DMA length */ dma_length = (reg[20] << 8) | reg[19]; - /* Zero DMA length */ + /* Zero DMA length (pre-decrementing counter) */ if (!dma_length) { dma_length = 0x10000; @@ -894,8 +916,7 @@ void vdp_z80_ctrl_w(unsigned int data) /* DMA source address */ dma_src = (reg[22] << 8) | reg[21]; - /* trigger DMA copy */ - dma_type = 3; + /* Trigger DMA */ vdp_dma_update(Z80.cycles); break; } @@ -1242,10 +1263,15 @@ unsigned int vdp_68k_ctrl_r(unsigned int cycles) vdp_fifo_update(cycles); } - /* Update DMA Busy flag */ - if ((status & 2) && !dma_length && (cycles >= dma_endCycles)) + /* Check if DMA Busy flag is set */ + if (status & 2) { - status &= 0xFFFD; + /* Check if DMA is finished */ + if (!dma_length && (cycles >= dma_endCycles)) + { + /* Clear DMA Busy flag */ + status &= 0xFFFD; + } } /* Return VDP status */ @@ -1283,10 +1309,15 @@ unsigned int vdp_z80_ctrl_r(unsigned int cycles) /* Cycle-accurate SOVR & VINT flags */ int line = (lines_per_frame + (cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame; - /* Update DMA Busy flag (Mega Drive VDP specific) */ - if ((system_hw & SYSTEM_MD) && (status & 2) && !dma_length && (cycles >= dma_endCycles)) + /* Check if DMA busy flag is set (Mega Drive VDP specific) */ + if (status & 2) { - status &= 0xFD; + /* Check if DMA is finished */ + if (!dma_length && (cycles >= dma_endCycles)) + { + /* Clear DMA Busy flag */ + status &= 0xFD; + } } /* Check if we are already on next line */ @@ -1300,7 +1331,7 @@ unsigned int vdp_z80_ctrl_r(unsigned int cycles) } else if ((line >= 0) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special)) { - /* Check sprites overflow & collision */ + /* render next line to check sprites overflow & collision */ render_line(line); } } @@ -2417,23 +2448,22 @@ static void vdp_68k_data_w_m5(unsigned int data) /* Write data */ vdp_bus_w(data); - /* DMA Fill */ - if (dmafill & 0x100) + /* Check if DMA Fill is pending */ + if (dmafill) { - /* Fill data = MSB (DMA fill flag is cleared) */ - dmafill = data >> 8; + /* Clear DMA Fill pending flag */ + dmafill = 0; /* DMA length */ dma_length = (reg[20] << 8) | reg[19]; - /* Zero DMA length */ + /* Zero DMA length (pre-decrementing counter) */ if (!dma_length) { dma_length = 0x10000; } - /* Process DMA Fill*/ - dma_type = 2; + /* Trigger DMA */ vdp_dma_update(m68k.cycles); } } @@ -2694,23 +2724,22 @@ static void vdp_z80_data_w_m5(unsigned int data) /* Increment address register */ addr += reg[15]; - /* DMA Fill */ - if (dmafill & 0x100) + /* Check if DMA Fill is pending */ + if (dmafill) { - /* Fill data (DMA fill flag is cleared) */ - dmafill = data; + /* Clear DMA Fill pending flag */ + dmafill = 0; /* DMA length */ dma_length = (reg[20] << 8) | reg[19]; - /* Zero DMA length */ + /* Zero DMA length (pre-decrementing counter) */ if (!dma_length) { dma_length = 0x10000; } - /* Process DMA Fill */ - dma_type = 2; + /* Trigger DMA */ vdp_dma_update(Z80.cycles); } } @@ -3074,11 +3103,11 @@ static void vdp_dma_68k_io(unsigned int length) dma_src = (source >> 1) & 0xffff; } -/* VRAM Copy (TODO: check if CRAM or VSRAM copy is possible) */ +/* VRAM Copy */ static void vdp_dma_copy(unsigned int length) { - /* VRAM read/write operation only */ - if ((code & 0x1E) == 0x10) + /* CD4 should be set (CD0-CD3 ignored) otherwise VDP locks (hard reset needed) */ + if (code & 0x10) { int name; uint8 data; @@ -3088,52 +3117,9 @@ static void vdp_dma_copy(unsigned int length) do { - /* Read byte from source address */ - data = READ_BYTE(vram, source); + /* Read byte from adjacent VRAM source address */ + data = READ_BYTE(vram, source ^ 1); - /* Intercept writes to Sprite Attribute Table */ - if ((addr & sat_base_mask) == satb) - { - /* Update internal SAT */ - WRITE_BYTE(sat, addr & sat_addr_mask, data); - } - - /* Write byte to VRAM address */ - WRITE_BYTE(vram, addr, data); - - /* Update pattern cache */ - MARK_BG_DIRTY(addr); - - /* Increment source address */ - source++; - - /* Increment VRAM address */ - addr += reg[15]; - } - while (--length); - - /* Update DMA source address */ - dma_src = source; - } - else - { - /* DMA source & VRAM addresses are still incremented */ - addr += reg[15] * length; - dma_src += length; - } -} - -/* VRAM Fill (TODO: check if CRAM or VSRAM fill is possible) */ -static void vdp_dma_fill(unsigned int length) -{ - /* VRAM write operation only (Williams Greatest Hits after soft reset) */ - if ((code & 0x1F) == 0x01) - { - int name; - uint8 data = dmafill; - - do - { /* Intercept writes to Sprite Attribute Table */ if ((addr & sat_base_mask) == satb) { @@ -3141,20 +3127,126 @@ static void vdp_dma_fill(unsigned int length) WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data); } - /* Write byte to adjacent VRAM address */ + /* Write byte to adjacent VRAM destination address */ WRITE_BYTE(vram, addr ^ 1, data); /* Update pattern cache */ - MARK_BG_DIRTY (addr); + MARK_BG_DIRTY(addr); - /* Increment VRAM address */ + /* Increment VRAM source address */ + source++; + + /* Increment VRAM destination address */ addr += reg[15]; } while (--length); - } - else - { - /* VRAM address is still incremented */ - addr += reg[15] * length; + + /* Update DMA source address */ + dma_src = source; + } +} + +/* DMA Fill */ +static void vdp_dma_fill(unsigned int length) +{ + /* Check destination code (CD0-CD3) */ + switch (code & 0x0F) + { + case 0x01: /* VRAM */ + { + int name; + + /* Get source data from last written FIFO entry */ + uint8 data = fifo[(fifo_idx+3)&3] >> 8; + + do + { + /* Intercept writes to Sprite Attribute Table */ + if ((addr & sat_base_mask) == satb) + { + /* Update internal SAT */ + WRITE_BYTE(sat, (addr & sat_addr_mask) ^ 1, data); + } + + /* Write byte to adjacent VRAM address */ + WRITE_BYTE(vram, addr ^ 1, data); + + /* Update pattern cache */ + MARK_BG_DIRTY (addr); + + /* Increment VRAM address */ + addr += reg[15]; + } + while (--length); + break; + } + + case 0x03: /* CRAM */ + { + /* Get source data from next available FIFO entry */ + uint16 data = fifo[fifo_idx]; + + /* Pack 16-bit bus data (BBB0GGG0RRR0) to 9-bit CRAM data (BBBGGGRRR) */ + data = ((data & 0xE00) >> 3) | ((data & 0x0E0) >> 2) | ((data & 0x00E) >> 1); + + do + { + /* Pointer to CRAM 9-bit word */ + uint16 *p = (uint16 *)&cram[addr & 0x7E]; + + /* Check if CRAM data is being modified */ + if (data != *p) + { + /* CRAM index (64 words) */ + int index = (addr >> 1) & 0x3F; + + /* Write CRAM data */ + *p = data; + + /* Color entry 0 of each palette is never displayed (transparent pixel) */ + if (index & 0x0F) + { + /* Update color palette */ + color_update_m5(index, data); + } + + /* Update backdrop color */ + if (index == border) + { + color_update_m5(0x00, data); + } + } + + /* Increment CRAM address */ + addr += reg[15]; + } + while (--length); + break; + } + + case 0x05: /* VSRAM */ + { + /* Get source data from next available FIFO entry */ + uint16 data = fifo[fifo_idx]; + + do + { + /* Write VSRAM data */ + *(uint16 *)&vsram[addr & 0x7E] = data; + + /* Increment VSRAM address */ + addr += reg[15]; + } + while (--length); + break; + } + + default: + { + /* invalid destination does nothing (Williams Greatest Hits after soft reset) */ + + /* address is still incremented */ + addr += reg[15] * length; + } } } From a43bad325cd3a10ba59213225754df8519fef921 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:09:50 +0200 Subject: [PATCH 21/39] [Core/MCD] improved Main-CPU & Sub-CPU idle loop detection (fixes "Super League CD") --- core/cd_hw/scd.c | 60 ++++++++++++++++++++++---------------- core/m68k/m68kops.h | 48 ++++++++++++++++++++++++++++-- core/mem68k.c | 71 +++++++++++++++++++++++---------------------- 3 files changed, 117 insertions(+), 62 deletions(-) diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index 47ed230..c36c0d4 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -186,21 +186,31 @@ static void bram_write_word(unsigned int address, unsigned int data) /* PCM chip & Gate-Array area */ /*--------------------------------------------------------------------------*/ -static void s68k_poll_detect(reg) +static void s68k_poll_detect(unsigned int reg_mask) { /* detect SUB-CPU register polling */ - if (s68k.poll.detected == (1 << reg)) + if (s68k.poll.detected & reg_mask) { if (s68k.cycles <= s68k.poll.cycle) { if (s68k.pc == s68k.poll.pc) { - /* stop SUB-CPU until register is modified by MAIN-CPU */ + /* SUB-CPU polling confirmed ? */ + if (s68k.poll.detected & 1) + { + /* idle SUB-CPU until register is modified */ + s68k.cycles = s68k.cycle_end; + s68k.stopped = reg_mask; #ifdef LOG_SCD - error("s68k stopped from %d cycles\n", s68k.cycles); + error("s68k stopped from %d cycles\n", s68k.cycles); #endif - s68k.cycles = s68k.cycle_end; - s68k.stopped = 1 << reg; + } + else + { + /* confirm SUB-CPU polling */ + s68k.poll.detected |= 1; + s68k.poll.cycle = s68k.cycles + 392; + } } return; } @@ -208,15 +218,15 @@ static void s68k_poll_detect(reg) else { /* set SUB-CPU register access flag */ - s68k.poll.detected = 1 << reg; + s68k.poll.detected = reg_mask; } - /* restart SUB-CPU polling detection */ + /* reset SUB-CPU polling detection */ s68k.poll.cycle = s68k.cycles + 392; s68k.poll.pc = s68k.pc; } -static void s68k_poll_sync(reg) +static void s68k_poll_sync(unsigned int reg_mask) { /* relative MAIN-CPU cycle counter */ unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE; @@ -227,8 +237,8 @@ static void s68k_poll_sync(reg) m68k_run(cycles); } - /* MAIN-CPU stopped on register polling ? */ - if (m68k.stopped & (3 << reg)) + /* MAIN-CPU idle on register polling ? */ + if (m68k.stopped & reg_mask) { /* sync MAIN-CPU with SUB-CPU */ m68k.cycles = cycles; @@ -240,9 +250,9 @@ static void s68k_poll_sync(reg) #endif } - /* clear CPU register(s) access flags */ - m68k.poll.detected &= ~(3 << reg); - s68k.poll.detected &= ~(3 << reg); + /* clear CPU register access flags */ + s68k.poll.detected &= ~reg_mask; + m68k.poll.detected &= ~reg_mask; } static unsigned int scd_read_byte(unsigned int address) @@ -266,14 +276,14 @@ static unsigned int scd_read_byte(unsigned int address) /* Memory Mode */ if (address == 0xff8003) { - s68k_poll_detect(0x03); + s68k_poll_detect(1<<0x03); return scd.regs[0x03>>1].byte.l; } /* MAIN-CPU communication flags */ if (address == 0xff800e) { - s68k_poll_detect(0x0e); + s68k_poll_detect(1<<0x0e); return scd.regs[0x0e>>1].byte.h; } @@ -328,7 +338,7 @@ static unsigned int scd_read_byte(unsigned int address) /* MAIN-CPU communication words */ if ((address & 0x1f0) == 0x10) { - s68k_poll_detect(address & 0x1f); + s68k_poll_detect(1 << (address & 0x1f)); } /* default registers */ @@ -358,7 +368,7 @@ static unsigned int scd_read_word(unsigned int address) /* Memory Mode */ if (address == 0xff8002) { - s68k_poll_detect(0x03); + s68k_poll_detect(1<<0x03); return scd.regs[0x03>>1].w; } @@ -418,7 +428,7 @@ static unsigned int scd_read_word(unsigned int address) m68k_run(cycles); } - s68k_poll_detect(address & 0x1e); + s68k_poll_detect(3 << (address & 0x1e)); } /* default registers */ @@ -526,7 +536,7 @@ static void scd_write_byte(unsigned int address, unsigned int data) case 0x03: /* Memory Mode */ { - s68k_poll_sync(0x02); + s68k_poll_sync(1<<0x03); /* detect MODE & RET bits modifications */ if ((data ^ scd.regs[0x03 >> 1].byte.l) & 0x05) @@ -687,7 +697,7 @@ static void scd_write_byte(unsigned int address, unsigned int data) case 0x0f: /* SUB-CPU communication flags */ { - s68k_poll_sync(0x0e); + s68k_poll_sync(1<<0x0f); scd.regs[0x0f>>1].byte.l = data; return; } @@ -748,7 +758,7 @@ static void scd_write_byte(unsigned int address, unsigned int data) /* SUB-CPU communication words */ if ((address & 0xf0) == 0x20) { - s68k_poll_sync((address - 0x10) & 0x1e); + s68k_poll_sync(1 << ((address - 0x10) & 0x1f)); } /* default registers */ @@ -799,7 +809,7 @@ static void scd_write_word(unsigned int address, unsigned int data) case 0x02: /* Memory Mode */ { - s68k_poll_sync(0x02); + s68k_poll_sync(1<<0x03); /* detect MODE & RET bits modifications */ if ((data ^ scd.regs[0x03>>1].byte.l) & 0x05) @@ -965,7 +975,7 @@ static void scd_write_word(unsigned int address, unsigned int data) case 0x0e: /* SUB-CPU communication flags */ { - s68k_poll_sync(0x0e); + s68k_poll_sync(1<<0x0f); /* MSB is read-only */ scd.regs[0x0f>>1].byte.l = data; @@ -1032,7 +1042,7 @@ static void scd_write_word(unsigned int address, unsigned int data) /* SUB-CPU communication words */ if ((address & 0xf0) == 0x20) { - s68k_poll_sync((address - 0x10) & 0x1e); + s68k_poll_sync(3 << ((address - 0x10) & 0x1e)); } /* default registers */ diff --git a/core/m68k/m68kops.h b/core/m68k/m68kops.h index 57ca5ce..fd5110e 100644 --- a/core/m68k/m68kops.h +++ b/core/m68k/m68kops.h @@ -7220,15 +7220,15 @@ static void m68k_op_dbf_16(void) uint res = MASK_OUT_ABOVE_16(*r_dst - 1); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; - /* reset idle loop detection */ - m68ki_cpu.poll.detected = 0; - if(res != 0xffff) { uint offset = OPER_I_16(); REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7250,6 +7250,9 @@ static void m68k_op_dbhi_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7274,6 +7277,9 @@ static void m68k_op_dbls_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7298,6 +7304,9 @@ static void m68k_op_dbcc_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7322,6 +7331,9 @@ static void m68k_op_dbcs_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7346,6 +7358,9 @@ static void m68k_op_dbne_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7370,6 +7385,9 @@ static void m68k_op_dbeq_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7394,6 +7412,9 @@ static void m68k_op_dbvc_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7418,6 +7439,9 @@ static void m68k_op_dbvs_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7442,6 +7466,9 @@ static void m68k_op_dbpl_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7466,6 +7493,9 @@ static void m68k_op_dbmi_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7490,6 +7520,9 @@ static void m68k_op_dbge_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7514,6 +7547,9 @@ static void m68k_op_dblt_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7538,6 +7574,9 @@ static void m68k_op_dbgt_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; @@ -7562,6 +7601,9 @@ static void m68k_op_dble_16(void) REG_PC -= 2; m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); + + /* reset idle loop detection */ + m68ki_cpu.poll.detected = 0; return; } REG_PC += 2; diff --git a/core/mem68k.c b/core/mem68k.c index 3f1f29a..0004d03 100644 --- a/core/mem68k.c +++ b/core/mem68k.c @@ -223,28 +223,31 @@ void z80_write_word(unsigned int address, unsigned int data) /* I/O Control */ /*--------------------------------------------------------------------------*/ -static void m68k_poll_detect(reg) +static void m68k_poll_detect(unsigned int reg_mask) { /* detect MAIN-CPU register polling */ - if (m68k.poll.detected == (1 << reg)) + if (m68k.poll.detected & reg_mask) { if (m68k.cycles <= m68k.poll.cycle) { if (m68k.pc == m68k.poll.pc) { - /* stop MAIN-CPU until register is modified by SUB-CPU */ -#ifdef LOG_SCD - error("m68k stopped from %d cycles\n", m68k.cycles); -#endif - m68k.cycles = m68k.cycle_end; - m68k.stopped = 1 << reg; - - /* return to current instruction */ - do + /* MAIN-CPU polling confirmed ? */ + if (m68k.poll.detected & 1) { - m68k.pc -= 2; + /* idle MAIN-CPU until register is modified */ + m68k.cycles = m68k.cycle_end; + m68k.stopped = reg_mask; +#ifdef LOG_SCD + error("m68k stopped from %d cycles\n", m68k.cycles); +#endif + } + else + { + /* confirm MAIN-CPU polling */ + m68k.poll.detected |= 1; + m68k.poll.cycle = m68k.cycles + 840; } - while (m68k.ir != *(uint16 *)(m68k.memory_map[(m68k.pc>>16)&0xff].base + (m68k.pc & 0xffff))); } return; } @@ -252,15 +255,15 @@ static void m68k_poll_detect(reg) else { /* set MAIN-CPU register access flag */ - m68k.poll.detected = 1 << reg; + m68k.poll.detected = reg_mask; } - /* restart MAIN-CPU polling detection */ + /* reset MAIN-CPU polling detection */ m68k.poll.cycle = m68k.cycles + 840; m68k.poll.pc = m68k.pc; } -static void m68k_poll_sync(reg) +static void m68k_poll_sync(unsigned int reg_mask) { /* relative SUB-CPU cycle counter */ unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; @@ -271,8 +274,8 @@ static void m68k_poll_sync(reg) s68k_run(cycles); } - /* SUB-CPU stopped on register polling ? */ - if (s68k.stopped & (3 << reg)) + /* SUB-CPU idle on register polling ? */ + if (s68k.stopped & reg_mask) { /* sync SUB-CPU with MAIN-CPU */ s68k.cycles = cycles; @@ -284,9 +287,9 @@ static void m68k_poll_sync(reg) #endif } - /* clear CPU register(s) access flags */ - m68k.poll.detected &= ~(3 << reg); - s68k.poll.detected &= ~(3 << reg); + /* clear CPU register access flags */ + s68k.poll.detected &= ~reg_mask; + m68k.poll.detected &= ~reg_mask; } unsigned int ctrl_io_read_byte(unsigned int address) @@ -335,7 +338,7 @@ unsigned int ctrl_io_read_byte(unsigned int address) /* Memory Mode */ if (index == 0x03) { - m68k_poll_detect(0x03); + m68k_poll_detect(1<<0x03); return scd.regs[0x03>>1].byte.l; } @@ -345,13 +348,13 @@ unsigned int ctrl_io_read_byte(unsigned int address) /* relative SUB-CPU cycle counter */ unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - /* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 OS ROM) */ + /* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 Boot ROM) */ if (!s68k.stopped && (s68k.cycles < cycles)) { s68k_run(cycles); } - m68k_poll_detect(0x0f); + m68k_poll_detect(1<<0x0f); return scd.regs[0x0f>>1].byte.l; } @@ -361,7 +364,7 @@ unsigned int ctrl_io_read_byte(unsigned int address) /* SUB-CPU communication words */ if (index >= 0x20) { - m68k_poll_detect(index - 0x10); + m68k_poll_detect(1 << (index - 0x10)); } /* register LSB */ @@ -466,7 +469,7 @@ unsigned int ctrl_io_read_word(unsigned int address) /* Memory Mode */ if (index == 0x02) { - m68k_poll_detect(0x03); + m68k_poll_detect(1<<0x03); return scd.regs[0x03>>1].w; } @@ -498,7 +501,7 @@ unsigned int ctrl_io_read_word(unsigned int address) /* SUB-CPU communication words */ if (index >= 0x20) { - m68k_poll_detect(index - 0x10); + m68k_poll_detect(3 << (index - 0x10)); } return scd.regs[index >> 1].w; @@ -611,7 +614,7 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) /* relative SUB-CPU cycle counter */ unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - /* sync SUB-CPU with MAIN-CPU */ + /* sync SUB-CPU with MAIN-CPU (Earnest Evans, Fhey Area) */ if (!s68k.stopped && (s68k.cycles < cycles)) { s68k_run(cycles); @@ -674,7 +677,7 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) case 0x03: /* Memory mode */ { - m68k_poll_sync(0x02); + m68k_poll_sync(1<<0x03); /* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */ m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11); @@ -726,7 +729,7 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) case 0x0e: /* MAIN-CPU communication flags */ { - m68k_poll_sync(0x0e); + m68k_poll_sync(1<<0x0e); scd.regs[0x0e>>1].byte.h = data; return; } @@ -736,7 +739,7 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) /* MAIN-CPU communication words */ if ((address & 0x30) == 0x10) { - m68k_poll_sync(address & 0x1e); + m68k_poll_sync(1 << (address & 0x1f)); /* register LSB */ if (address & 1) @@ -887,7 +890,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) case 0x02: /* Memory Mode */ { - m68k_poll_sync(0x02); + m68k_poll_sync(1<<0x03); /* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */ m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11); @@ -939,7 +942,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) case 0x0e: /* MAIN-CPU communication flags */ { - m68k_poll_sync(0x0e); + m68k_poll_sync(1<<0x0e); /* LSB is read-only (Mortal Kombat) */ scd.regs[0x0e>>1].byte.h = data; @@ -951,7 +954,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) /* MAIN-CPU communication words */ if ((address & 0x30) == 0x10) { - m68k_poll_sync(address & 0x1e); + m68k_poll_sync(3 << (address & 0x1e)); scd.regs[(address >> 1) & 0xff].w = data; return; } From f7fc3382fc1d925fc59afb9e35a97cd45ed4c1ec Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:14:44 +0200 Subject: [PATCH 22/39] [Core/MCD] added CDC & GFX register polling detection / synchronization --- core/cd_hw/cdc.c | 15 ++++++++++++++- core/cd_hw/gfx.c | 13 +++++++++++++ core/cd_hw/scd.c | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/core/cd_hw/cdc.c b/core/cd_hw/cdc.c index c8c75e6..3425931 100644 --- a/core/cd_hw/cdc.c +++ b/core/cd_hw/cdc.c @@ -214,9 +214,22 @@ void cdc_dma_update(void) } } - /* clear DSR bit & set EDT bit (SCD register $04) */ + /* clear DSR bit & set EDT bit (CD register $04) */ scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80; + /* SUB-CPU idle on register $04 polling ? */ + if (s68k.stopped & (1<<0x04)) + { + /* sync SUB-CPU with CDC */ + s68k.cycles = scd.cycles; + + /* restart SUB-CPU */ + s68k.stopped = 0; +#ifdef LOG_SCD + error("s68k started from %d cycles\n", s68k.cycles); +#endif + } + /* disable DMA transfer */ cdc.dma_w = 0; } diff --git a/core/cd_hw/gfx.c b/core/cd_hw/gfx.c index d1f0341..4b40c88 100644 --- a/core/cd_hw/gfx.c +++ b/core/cd_hw/gfx.c @@ -692,6 +692,19 @@ void gfx_update(int cycles) /* end of graphics operation */ scd.regs[0x58>>1].byte.h = 0; + /* SUB-CPU idle on register $58 polling ? */ + if (s68k.stopped & (1<<0x08)) + { + /* sync SUB-CPU with GFX chip */ + s68k.cycles = scd.cycles; + + /* restart SUB-CPU */ + s68k.stopped = 0; +#ifdef LOG_SCD + error("s68k started from %d cycles\n", s68k.cycles); +#endif + } + /* level 1 interrupt enabled ? */ if (scd.regs[0x32>>1].byte.l & 0x02) { diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index c36c0d4..e750374 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -287,6 +287,20 @@ static unsigned int scd_read_byte(unsigned int address) return scd.regs[0x0e>>1].byte.h; } + /* CDC transfer status */ + if (address == 0xff8004) + { + s68k_poll_detect(1<<0x04); + return scd.regs[0x04>>1].byte.h; + } + + /* GFX operation status */ + if (address == 0xff8058) + { + s68k_poll_detect(1<<0x08); + return scd.regs[0x58>>1].byte.h; + } + /* CDC register data (controlled by BIOS, byte access only ?) */ if (address == 0xff8007) { From 754d2a116875fb56a806d909d1100c022188536d Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:19:23 +0200 Subject: [PATCH 23/39] [Core/MCD] fixed pending level 1 interrupts when GFX interrupt is disabled (fixes random freezes out of "Batman Returns" option menu) --- core/cd_hw/scd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index e750374..3cb1f1a 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -739,7 +739,10 @@ static void scd_write_byte(unsigned int address, unsigned int data) /* update IEN2 flag */ scd.regs[0x00].byte.h = (scd.regs[0x00].byte.h & 0x7f) | ((data & 0x04) << 5); - + + /* clear level 1 interrupt if disabled ("Batman Returns" option menu) */ + scd.pending &= ~(data & 0x02); + /* update IRQ level */ s68k_update_irq((scd.pending & data) >> 1); return; @@ -1025,6 +1028,9 @@ static void scd_write_word(unsigned int address, unsigned int data) /* update IEN2 flag */ scd.regs[0x00].byte.h = (scd.regs[0x00].byte.h & 0x7f) | ((data & 0x04) << 5); + + /* clear pending level 1 interrupt if disabled ("Batman Returns" option menu) */ + scd.pending &= ~(data & 0x02); /* update IRQ level */ s68k_update_irq((scd.pending & data) >> 1); From 20dd11e5582c9035dd408b36fe5d81134ea2b9e7 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:20:28 +0200 Subject: [PATCH 24/39] [Core/MCD] improved Sub-CPU synchronization with Main-CPU (fixes "Soul Star") --- core/mem68k.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/mem68k.c b/core/mem68k.c index 0004d03..60f0763 100644 --- a/core/mem68k.c +++ b/core/mem68k.c @@ -498,6 +498,15 @@ unsigned int ctrl_io_read_word(unsigned int address) /* default registers */ if (index < 0x30) { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Soul Star) */ + if (!s68k.stopped && (s68k.cycles < cycles)) + { + s68k_run(cycles); + } + /* SUB-CPU communication words */ if (index >= 0x20) { From 5fbde4e1879270b19a3ee244409519fb96bab0c2 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:25:08 +0200 Subject: [PATCH 25/39] [Core/MCD] fixed access to "write-only" communication flags from Main-CPU & SUB-CPU (verified on real hardware by Notaz) --- core/cd_hw/scd.c | 15 +++++---------- core/mem68k.c | 15 +++++---------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index 3cb1f1a..975de03 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -703,13 +703,8 @@ static void scd_write_byte(unsigned int address, unsigned int data) return; } - case 0x0e: /* MAIN-CPU communication flags, normally read-only (Space Ace, Dragon's Lair) */ - { - /* ROR8 operation */ - data = (data >> 1) | ((data << 7) & 1); - } - - case 0x0f: /* SUB-CPU communication flags */ + case 0x0e: /* SUB-CPU communication flags */ + case 0x0f: /* !LWR is ignored (Space Ace, Dragon's Lair) */ { s68k_poll_sync(1<<0x0f); scd.regs[0x0f>>1].byte.l = data; @@ -990,12 +985,12 @@ static void scd_write_word(unsigned int address, unsigned int data) return; } - case 0x0e: /* SUB-CPU communication flags */ + case 0x0e: /* CPU Communication flags */ { s68k_poll_sync(1<<0x0f); - /* MSB is read-only */ - scd.regs[0x0f>>1].byte.l = data; + /* D8-D15 ignored -> only SUB-CPU flags are updated */ + scd.regs[0x0f>>1].byte.l = data & 0xff; return; } diff --git a/core/mem68k.c b/core/mem68k.c index 60f0763..0a31466 100644 --- a/core/mem68k.c +++ b/core/mem68k.c @@ -730,13 +730,8 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) return; } - case 0x0f: /* SUB-CPU communication flags, normally read-only (Space Ace, Dragon's Lair) */ - { - /* ROL8 operation */ - data = (data << 1) | ((data >> 7) & 1); - } - - case 0x0e: /* MAIN-CPU communication flags */ + case 0x0e: /* MAIN-CPU communication flags */ + case 0x0f: /* !LWR is ignored (Space Ace, Dragon's Lair) */ { m68k_poll_sync(1<<0x0e); scd.regs[0x0e>>1].byte.h = data; @@ -949,12 +944,12 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) return; } - case 0x0e: /* MAIN-CPU communication flags */ + case 0x0e: /* CPU communication flags */ { m68k_poll_sync(1<<0x0e); - /* LSB is read-only (Mortal Kombat) */ - scd.regs[0x0e>>1].byte.h = data; + /* D8-D15 ignored -> only MAIN-CPU flags are updated (Mortal Kombat) */ + scd.regs[0x0e>>1].byte.h = data & 0xff; return; } From cf6081fb6921f720ae53d312f75d4e2e3ce86ceb Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:27:10 +0200 Subject: [PATCH 26/39] [Core/MCD] disabled CD hardware reset on Soft-Reset (verified on real hardware) --- core/cd_hw/scd.c | 5 +++++ core/genesis.c | 21 +++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index 975de03..321d7bc 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -1218,6 +1218,11 @@ void scd_reset(int hard) m68k.memory_map[i].base = scd.prg_ram; m68k.memory_map[i+1].base = scd.prg_ram + 0x10000; } + + /* reset & halt SUB-CPU */ + s68k.cycles = 0; + s68k_pulse_reset(); + s68k_pulse_halt(); } else { diff --git a/core/genesis.c b/core/genesis.c index 729d59b..f15f2f7 100644 --- a/core/genesis.c +++ b/core/genesis.c @@ -253,19 +253,16 @@ void gen_reset(int hard_reset) { if (system_hw == SYSTEM_MCD) { - /* reset CD hardware */ - scd_reset(1); - - /* reset & halt SUB-CPU */ - s68k.cycles = 0; - s68k_pulse_reset(); - s68k_pulse_halt(); - } - else - { - /* reset MD cartridge hardware */ - md_cart_reset(hard_reset); + /* FRES is only asserted on Power ON */ + if (hard_reset) + { + /* reset CD hardware */ + scd_reset(1); + } } + + /* reset MD cartridge hardware */ + md_cart_reset(hard_reset); /* Z80 bus is released & Z80 is reseted */ m68k.memory_map[0xa0].read8 = m68k_read_bus_8; From 3aa1529aa171df6f78b8a28f2b1bbe2ec843bf20 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:32:39 +0200 Subject: [PATCH 27/39] [Core/VDP] added some 68k cycles delay on invalid VRAM writes to simulate periodical 68k wait-states (fixes "Microcosm" intro loop) --- core/vdp_ctrl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index 0b7b76a..f0d74e3 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -2188,7 +2188,6 @@ static void vdp_fifo_update(unsigned int cycles) /*--------------------------------------------------------------------------*/ /* Internal 16-bit data bus access function (Mode 5 only) */ /*--------------------------------------------------------------------------*/ - static void vdp_bus_w(unsigned int data) { /* write data to next FIFO entry */ @@ -2290,7 +2289,7 @@ static void vdp_bus_w(unsigned int data) if (reg[11] & 0x04) { /* VSRAM writes during HBLANK (Adventures of Batman & Robin) */ - if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (m68k.cycles <= (mcycles_vdp + 860))) + if ((v_counter < bitmap.viewport.h) && (reg[1] & 0x40) && (m68k.cycles <= (mcycles_vdp + 860))) { /* Remap current line */ render_line(v_counter); @@ -2304,6 +2303,8 @@ static void vdp_bus_w(unsigned int data) default: { + /* add some delay until 68k periodical wait-states (RAM refresh ?) are accurately emulated (needed by "Clue" & "Microcosm") */ + m68k.cycles += 2; #ifdef LOGERROR error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, data, m68k_get_reg(M68K_REG_PC)); #endif From 9be11710f20ce05e10c21fea46b012dd2540749a Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 21 Oct 2013 00:35:32 +0200 Subject: [PATCH 28/39] [Core/MD] bump-up savestate version --- core/state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state.h b/core/state.h index 63ebd3e..678d632 100644 --- a/core/state.h +++ b/core/state.h @@ -40,7 +40,7 @@ #define _STATE_H_ #define STATE_SIZE 0xfd000 -#define STATE_VERSION "GENPLUS-GX 1.7.1" +#define STATE_VERSION "GENPLUS-GX 1.7.5" #define load_param(param, size) \ memcpy(param, &state[bufferptr], size); \ From a8184dad2ea63d3f1e3d89bf3a8e44e0a1c44cb8 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 28 Oct 2013 22:06:28 +0100 Subject: [PATCH 29/39] [Core/VDP] added some precision in comments about delay on invalid VRAM writes --- core/vdp_ctrl.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/core/vdp_ctrl.c b/core/vdp_ctrl.c index f0d74e3..4a80ae3 100644 --- a/core/vdp_ctrl.c +++ b/core/vdp_ctrl.c @@ -805,11 +805,17 @@ void vdp_68k_ctrl_w(unsigned int data) /* FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch, Sol Deace) -------------------------------------------------------------------------- - Each VRAM access is byte wide, so one VRAM write (word) need twice cycles. + Each VRAM access is byte wide, so one VRAM write (word) need two slot access. - Note: Invalid code 0x02 (register write) apparently behaves the same as VRAM - access, although no data is written in this case (fixes Clue menu) - */ + NOTE: Invalid code 0x02 (register write) should not behave the same as VRAM + access, i.e data is ignored and only one access slot is used for each word, + BUT a few games ("Clue", "Microcosm") which accidentally corrupt code value + will have issues when emulating FIFO timings. They likely work fine on real + hardware because of periodical 68k wait-states which have been observed and + would naturaly add some delay between writes. Until those wait-states are + accurately measured and emulated, delay is forced when invalid code value + is being used. + */ fifo_byte_access = ((code & 0x0F) <= 0x02); } @@ -2303,7 +2309,7 @@ static void vdp_bus_w(unsigned int data) default: { - /* add some delay until 68k periodical wait-states (RAM refresh ?) are accurately emulated (needed by "Clue" & "Microcosm") */ + /* add some delay until 68k periodical wait-states are accurately emulated ("Clue", "Microcosm") */ m68k.cycles += 2; #ifdef LOGERROR error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, data, m68k_get_reg(M68K_REG_PC)); From 430726cdefbe5f353d6b1f0e02d81a8ddded8db7 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Mon, 28 Oct 2013 23:09:41 +0100 Subject: [PATCH 30/39] updated file header --- core/hvc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/hvc.h b/core/hvc.h index 9533626..85e9d02 100644 --- a/core/hvc.h +++ b/core/hvc.h @@ -3,7 +3,7 @@ * HV Counters * * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald - * Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: From f4e5694ae4c2f41968c542ac2601877b594c0590 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Tue, 29 Oct 2013 00:00:12 +0100 Subject: [PATCH 31/39] [Wii/Gamecube] DVD interface is now only initialized when needed --- gx/fileio/file_load.c | 7 +++++++ gx/main.c | 8 +------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/gx/fileio/file_load.c b/gx/fileio/file_load.c index 5c51afe..e896c4e 100644 --- a/gx/fileio/file_load.c +++ b/gx/fileio/file_load.c @@ -88,6 +88,13 @@ static int MountDVD(void) { GUI_MsgBoxOpen("Information", "Mounting DVD ...",1); + /* initialize DVD interface if needed */ +#ifdef HW_RVL + DI_Init(); +#else + DVD_Init(); +#endif + /* check if DVD is already mounted */ if (dvd_mounted) { diff --git a/gx/main.c b/gx/main.c index 1f222c7..be907b0 100644 --- a/gx/main.c +++ b/gx/main.c @@ -472,9 +472,8 @@ int main (int argc, char *argv[]) /* enable 64-byte fetch mode for L2 cache */ L2Enhance(); - /* initialize DI interface */ + /* disable DVD cache */ DI_UseCache(0); - DI_Init(); /* autodetect loader arguments */ if ((argc >= 3) && (argv[1] != NULL)) @@ -499,11 +498,6 @@ int main (int argc, char *argv[]) /* initialize video engine */ gx_video_Init(); -#ifndef HW_RVL - /* initialize DVD interface */ - DVD_Init(); -#endif - /* initialize input engine */ gx_input_Init(); From 587a6dca1b191913aebfb8fcf45b40fc599c60f5 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Wed, 30 Oct 2013 00:37:10 +0100 Subject: [PATCH 32/39] [Core/MCD] removed redundant checking on CPU sync --- core/cd_hw/scd.c | 12 ++++++------ core/mem68k.c | 40 ++++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index 321d7bc..1026506 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -232,7 +232,7 @@ static void s68k_poll_sync(unsigned int reg_mask) unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE; /* sync MAIN-CPU with SUB-CPU */ - if (!m68k.stopped && (m68k.cycles < cycles)) + if (!m68k.stopped) { m68k_run(cycles); } @@ -433,12 +433,12 @@ static unsigned int scd_read_word(unsigned int address) /* MAIN-CPU communication words */ if ((address & 0x1f0) == 0x10) { - /* relative MAIN-CPU cycle counter */ - unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE; - - /* sync MAIN-CPU with SUB-CPU (Mighty Morphin Power Rangers) */ - if (!m68k.stopped && (m68k.cycles < cycles)) + if (!m68k.stopped) { + /* relative MAIN-CPU cycle counter */ + unsigned int cycles = (s68k.cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE; + + /* sync MAIN-CPU with SUB-CPU (Mighty Morphin Power Rangers) */ m68k_run(cycles); } diff --git a/core/mem68k.c b/core/mem68k.c index 0a31466..78f2d82 100644 --- a/core/mem68k.c +++ b/core/mem68k.c @@ -269,7 +269,7 @@ static void m68k_poll_sync(unsigned int reg_mask) unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; /* sync SUB-CPU with MAIN-CPU */ - if (!s68k.stopped && (s68k.cycles < cycles)) + if (!s68k.stopped) { s68k_run(cycles); } @@ -345,12 +345,12 @@ unsigned int ctrl_io_read_byte(unsigned int address) /* SUB-CPU communication flags */ if (index == 0x0f) { - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 Boot ROM) */ - if (!s68k.stopped && (s68k.cycles < cycles)) + if (!s68k.stopped) { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Dracula Unleashed w/ Sega CD Model 2 Boot ROM) */ s68k_run(cycles); } @@ -498,18 +498,18 @@ unsigned int ctrl_io_read_word(unsigned int address) /* default registers */ if (index < 0x30) { - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* sync SUB-CPU with MAIN-CPU (Soul Star) */ - if (!s68k.stopped && (s68k.cycles < cycles)) - { - s68k_run(cycles); - } - /* SUB-CPU communication words */ if (index >= 0x20) { + if (!s68k.stopped) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Soul Star) */ + s68k_run(cycles); + } + m68k_poll_detect(3 << (index - 0x10)); } @@ -620,12 +620,12 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) /* level 2 interrupt enabled ? */ if (scd.regs[0x32>>1].byte.l & 0x04) { - /* relative SUB-CPU cycle counter */ - unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - - /* sync SUB-CPU with MAIN-CPU (Earnest Evans, Fhey Area) */ - if (!s68k.stopped && (s68k.cycles < cycles)) + if (!s68k.stopped) { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* sync SUB-CPU with MAIN-CPU (Earnest Evans, Fhey Area) */ s68k_run(cycles); } From 368af301453c5034628ac137f6b09d19fa470475 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Wed, 30 Oct 2013 00:38:41 +0100 Subject: [PATCH 33/39] [Core/SG] restored SG-1000 Pause button support --- core/system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/system.c b/core/system.c index 53a730b..d80a255 100644 --- a/core/system.c +++ b/core/system.c @@ -1137,7 +1137,7 @@ void system_frame_sms(int do_skip) } /* Detect pause button input (in Game Gear Mode, NMI is not generated) */ - if ((system_hw != SYSTEM_GG) && (system_hw != SYSTEM_SG)) + if (system_hw != SYSTEM_GG) { if (input.pad[0] & INPUT_START) { From 19d719e7f85af222118d8a968a7c64b553ec6be2 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Fri, 1 Nov 2013 13:01:49 +0100 Subject: [PATCH 34/39] [Wii/Gamecube] optimized GX frame rendering using display list --- gx/gx_video.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/gx/gx_video.c b/gx/gx_video.c index f356b0c..17cf065 100644 --- a/gx/gx_video.c +++ b/gx/gx_video.c @@ -355,6 +355,19 @@ static camera cam = { {0.0F, 0.0F, 0.0F} }; +/*** GX Display List ***/ +static u8 d_list[32] ATTRIBUTE_ALIGN(32) = +{ + GX_QUADS | GX_VTXFMT0, /* textured quad rendering (Vertex Format 0) */ + 0x00, 0x04, /* one quad = 4x vertex */ + 0x03, 0x00, 0x00, 0x00, 0x00, /* top left corner */ + 0x02, 0x00, 0x01, 0x00, 0x00, /* top right corner */ + 0x01, 0x00, 0x01, 0x00, 0x01, /* bottom right corner */ + 0x00, 0x00, 0x00, 0x00, 0x01, /* bottom left corner */ + 0x00, 0x00, 0x00, 0x00, 0x00, /* padding */ + 0x00, 0x00, 0x00, 0x00 +}; + /* VSYNC callback */ static void vi_callback(u32 cnt) { @@ -442,7 +455,7 @@ static void gxResetRendering(u8 type) /* uses array positionning, no alpha blending, no color channel (video emulation) */ GX_SetBlendMode(GX_BM_NONE,GX_BL_SRCALPHA,GX_BL_INVSRCALPHA,GX_LO_CLEAR); GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0); GX_SetVtxDesc(GX_VA_POS, GX_INDEX8); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_SetArray(GX_VA_POS, square, 3 * sizeof (s16)); @@ -1714,7 +1727,7 @@ int gx_video_Update(void) GX_InvalidateTexAll(); /* render textured quad */ - draw_square(); + GX_CallDispList(d_list, 32); /* lightgun # 1 screen mark */ if (crosshair[0]) From b63b9e738bbf16533ffa6d0a9f78a2491008caf4 Mon Sep 17 00:00:00 2001 From: EkeEke Date: Fri, 1 Nov 2013 13:06:15 +0100 Subject: [PATCH 35/39] [Wii/Gamecube] removed unused GX rendering code --- gx/gx_video.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/gx/gx_video.c b/gx/gx_video.c index 17cf065..cee3573 100644 --- a/gx/gx_video.c +++ b/gx/gx_video.c @@ -384,24 +384,6 @@ static void vi_callback(u32 cnt) video_sync = 0; } -/* Vertex Rendering */ -static inline void draw_vert(u8 pos, f32 s, f32 t) -{ - GX_Position1x8(pos); - GX_TexCoord2f32(s, t); -} - -/* textured quad rendering */ -static inline void draw_square(void) -{ - GX_Begin(GX_QUADS, GX_VTXFMT0, 4); - draw_vert(3, 0.0, 0.0); - draw_vert(2, 1.0, 0.0); - draw_vert(1, 1.0, 1.0); - draw_vert(0, 0.0, 1.0); - GX_End(); -} - /* Initialize GX */ static void gxStart(void) { From d507b8b6339cce45c3fcecaf05e15ff724ed0d4c Mon Sep 17 00:00:00 2001 From: EkeEke Date: Wed, 6 Nov 2013 01:13:38 +0100 Subject: [PATCH 36/39] [Core/VDP] fixed Game Gear display rendering regression when left/right borders are disabled --- core/vdp_render.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/vdp_render.c b/core/vdp_render.c index c6a9072..9496e51 100644 --- a/core/vdp_render.c +++ b/core/vdp_render.c @@ -4122,8 +4122,11 @@ void render_line(int line) } /* Horizontal borders */ - memset(&linebuf[0][0x20 - bitmap.viewport.x], 0x40, bitmap.viewport.x); - memset(&linebuf[0][0x20 + bitmap.viewport.w], 0x40, bitmap.viewport.x); + if (bitmap.viewport.x > 0) + { + memset(&linebuf[0][0x20 - bitmap.viewport.x], 0x40, bitmap.viewport.x); + memset(&linebuf[0][0x20 + bitmap.viewport.w], 0x40, bitmap.viewport.x); + } } else { From 352308bd38db2746f52a91096f83e32c9253a6c6 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 30 Nov 2013 01:48:37 +0100 Subject: [PATCH 37/39] (iOS) Add SDK min version flags --- Makefile.libretro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.libretro b/Makefile.libretro index 410a45e..426bda6 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -52,9 +52,9 @@ else ifeq ($(platform), ios) fpic := -fPIC SHARED := -dynamiclib -lz ENDIANNESS_DEFINES := -DLSB_FIRST - PLATFORM_DEFINES := -DHAVE_ZLIB + PLATFORM_DEFINES := -DHAVE_ZLIB -miphoneos-version-min=5.0 - CC = clang -arch armv7 -isysroot $(IOSSDK) + CC = clang -arch armv7 -isysroot $(IOSSDK) -miphoneos-version-min=5.0 else ifeq ($(platform), qnx) TARGET := $(TARGET_NAME)_libretro_qnx.so fpic := -fPIC From 2c401c1ff762f21f4aff1c5bbef20c906eadadb5 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 16 Dec 2013 12:28:19 +0100 Subject: [PATCH 38/39] Use new logging interface --- libretro/libretro.c | 46 ++++---- libretro/libretro.h | 280 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 296 insertions(+), 30 deletions(-) diff --git a/libretro/libretro.c b/libretro/libretro.c index 23fe934..7d12896 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -59,6 +59,7 @@ static const double ntsc_fps = 53693175.0 / (3420.0 * 262.0); static char g_rom_dir[1024]; +static retro_log_printf_t log_cb; static retro_video_refresh_t video_cb; static retro_input_poll_t input_poll_cb; static retro_input_state_t input_state_cb; @@ -72,12 +73,7 @@ static retro_audio_sample_batch_t audio_cb; void error(char * msg, ...) { -#ifndef _XBOX1 - va_list ap; - va_start(ap, msg); - vfprintf(stderr, msg, ap); - va_end(ap); -#endif + log_cb(RETRO_LOG_ERROR, msg); } int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension) @@ -98,11 +94,11 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten /* Mega CD BIOS are required files */ if (!strcmp(filename,CD_BIOS_US) || !strcmp(filename,CD_BIOS_EU) || !strcmp(filename,CD_BIOS_JP)) { - fprintf(stderr, "ERROR - Unable to open CD BIOS: %s.\n", filename); + log_cb(RETRO_LOG_ERROR, "Unable to open CD BIOS: %s.\n", filename); return 0; } - fprintf(stderr, "ERROR - Unable to open file.\n"); + log_cb(RETRO_LOG_ERROR, "Unable to open file.\n"); return 0; } @@ -114,11 +110,11 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten if(size > maxsize) { fclose(fd); - fprintf(stderr, "ERROR - File is too large.\n"); + log_cb(RETRO_LOG_ERROR, "File is too large.\n"); return 0; } - fprintf(stderr, "INFORMATION - Loading %d bytes ...\n", size); + log_cb(RETRO_LOG_INFO, "INFORMATION - Loading %d bytes ...\n", size); /* filename extension */ if (extension) @@ -857,7 +853,7 @@ bool retro_load_game(const struct retro_game_info *info) if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) || !dir) { - fprintf(stderr, "[genplus]: Defaulting system directory to %s.\n", g_rom_dir); + log_cb(RETRO_LOG_INFO, "[genplus]: Defaulting system directory to %s.\n", g_rom_dir); dir = g_rom_dir; } @@ -872,17 +868,17 @@ bool retro_load_game(const struct retro_game_info *info) snprintf(CD_BRAM_US, sizeof(CD_BRAM_US), "%s%cscd_U.brm", dir, slash); snprintf(CD_BRAM_JP, sizeof(CD_BRAM_JP), "%s%cscd_J.brm", dir, slash); snprintf(CART_BRAM, sizeof(CART_BRAM), "%s%ccart.brm", dir, slash); - fprintf(stderr, "Game Genie ROM should be located at: %s\n", GG_ROM); - fprintf(stderr, "Action Replay (Pro) ROM should be located at: %s\n", AR_ROM); - fprintf(stderr, "Sonic & Knuckles (2 MB) ROM should be located at: %s\n", SK_ROM); - fprintf(stderr, "Sonic & Knuckles UPMEM (256 KB) ROM should be located at: %s\n", SK_UPMEM); - fprintf(stderr, "Mega CD PAL BIOS should be located at: %s\n", CD_BIOS_EU); - fprintf(stderr, "Sega CD NTSC-U BIOS should be located at: %s\n", CD_BIOS_US); - fprintf(stderr, "Mega CD NTSC-J BIOS should be located at: %s\n", CD_BIOS_JP); - fprintf(stderr, "Mega CD PAL BRAM is located at: %s\n", CD_BRAM_EU); - fprintf(stderr, "Sega CD NTSC-U BRAM is located at: %s\n", CD_BRAM_US); - fprintf(stderr, "Mega CD NTSC-J BRAM is located at: %s\n", CD_BRAM_JP); - fprintf(stderr, "Mega CD RAM CART is located at: %s\n", CART_BRAM); + log_cb(RETRO_LOG_INFO, "Game Genie ROM should be located at: %s\n", GG_ROM); + log_cb(RETRO_LOG_INFO, "Action Replay (Pro) ROM should be located at: %s\n", AR_ROM); + log_cb(RETRO_LOG_INFO, "Sonic & Knuckles (2 MB) ROM should be located at: %s\n", SK_ROM); + log_cb(RETRO_LOG_INFO, "Sonic & Knuckles UPMEM (256 KB) ROM should be located at: %s\n", SK_UPMEM); + log_cb(RETRO_LOG_INFO, "Mega CD PAL BIOS should be located at: %s\n", CD_BIOS_EU); + log_cb(RETRO_LOG_INFO, "Sega CD NTSC-U BIOS should be located at: %s\n", CD_BIOS_US); + log_cb(RETRO_LOG_INFO, "Mega CD NTSC-J BIOS should be located at: %s\n", CD_BIOS_JP); + log_cb(RETRO_LOG_INFO, "Mega CD PAL BRAM is located at: %s\n", CD_BRAM_EU); + log_cb(RETRO_LOG_INFO, "Sega CD NTSC-U BRAM is located at: %s\n", CD_BRAM_US); + log_cb(RETRO_LOG_INFO, "Mega CD NTSC-J BRAM is located at: %s\n", CD_BRAM_JP); + log_cb(RETRO_LOG_INFO, "Mega CD RAM CART is located at: %s\n", CART_BRAM); check_variables(); if (!load_rom((char *)info->path)) @@ -950,6 +946,7 @@ size_t retro_get_memory_size(unsigned id) void retro_init(void) { + struct retro_log_callback log; unsigned level, rgb565; sms_ntsc = calloc(1, sizeof(sms_ntsc_t)); md_ntsc = calloc(1, sizeof(md_ntsc_t)); @@ -960,10 +957,13 @@ void retro_init(void) level = 1; environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level); + environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log); + log_cb = log.log; + #ifdef FRONTEND_SUPPORTS_RGB565 rgb565 = RETRO_PIXEL_FORMAT_RGB565; if(environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565)) - fprintf(stderr, "Frontend supports RGB565 - will use that instead of XRGB1555.\n"); + log_cb(RETRO_LOG_INFO, "Frontend supports RGB565 - will use that instead of XRGB1555.\n"); #endif } diff --git a/libretro/libretro.h b/libretro/libretro.h index b02855a..aaff348 100755 --- a/libretro/libretro.h +++ b/libretro/libretro.h @@ -1,3 +1,25 @@ +/* Copyright (C) 2010-2013 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this libretro API header (libretro.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + #ifndef LIBRETRO_H__ #define LIBRETRO_H__ @@ -72,6 +94,9 @@ extern "C" { // Eventually _PRESSED will return false for an index. No further presses are registered at this point. #define RETRO_DEVICE_POINTER 6 +// FIXME: Document this. +#define RETRO_DEVICE_SENSOR_ACCELEROMETER 7 + // These device types are specializations of the base types above. // They should only be used in retro_set_controller_type() to inform libretro implementations // about use of a very specific device type. @@ -128,6 +153,11 @@ extern "C" { #define RETRO_DEVICE_ID_POINTER_Y 1 #define RETRO_DEVICE_ID_POINTER_PRESSED 2 +// Id values for SENSOR types. +#define RETRO_DEVICE_ID_SENSOR_ACCELEROMETER_X 0 +#define RETRO_DEVICE_ID_SENSOR_ACCELEROMETER_Y 1 +#define RETRO_DEVICE_ID_SENSOR_ACCELEROMETER_Z 2 + // Returned from retro_get_region(). #define RETRO_REGION_NTSC 0 #define RETRO_REGION_PAL 1 @@ -335,6 +365,8 @@ enum retro_mod // If set, this call is not part of the public libretro API yet. It can change or be removed at any time. #define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000 +// Environment callback to be used internally in frontend. +#define RETRO_ENVIRONMENT_PRIVATE 0x20000 // Environment commands. #define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * -- @@ -412,10 +444,8 @@ enum retro_mod // Sets an interface which frontend can use to eject and insert disk images. // This is used for games which consist of multiple images and must be manually // swapped out by the user (e.g. PSX). -#define RETRO_ENVIRONMENT_SET_HW_RENDER (14 | RETRO_ENVIRONMENT_EXPERIMENTAL) +#define RETRO_ENVIRONMENT_SET_HW_RENDER 14 // struct retro_hw_render_callback * -- - // NOTE: This call is currently very experimental, and should not be considered part of the public API. - // The interface could be changed or removed at any time. // Sets an interface to let a libretro core render with hardware acceleration. // Should be called in retro_load_game(). // If successful, libretro cores will be able to render to a frontend-provided framebuffer. @@ -423,7 +453,7 @@ enum retro_mod // If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or NULL to retro_video_refresh_t. #define RETRO_ENVIRONMENT_GET_VARIABLE 15 // struct retro_variable * -- - // Interface to aquire user-defined information from environment + // Interface to acquire user-defined information from environment // that cannot feasibly be supported in a multi-system way. // 'key' should be set to a key which has already been set by SET_VARIABLES. // 'data' will be set to a value or NULL. @@ -452,12 +482,228 @@ enum retro_mod // Result is set to true if some variables are updated by // frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. // Variables should be queried with GET_VARIABLE. + // +#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 + // const bool * -- + // If true, the libretro implementation supports calls to retro_load_game() with NULL as argument. + // Used by cores which can run without particular game data. + // This should be called within retro_set_environment() only. + // +#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19 + // const char ** -- + // Retrieves the absolute path from where this libretro implementation was loaded. + // NULL is returned if the libretro was loaded statically (i.e. linked statically to frontend), or if the path cannot be determined. + // Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can be loaded without ugly hacks. + // + // +// Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. It was not used by any known core at the time, +// and was removed from the API. +#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 + // const struct retro_audio_callback * -- + // Sets an interface which is used to notify a libretro core about audio being available for writing. + // The callback can be called from any thread, so a core using this must have a thread safe audio implementation. + // It is intended for games where audio and video are completely asynchronous and audio can be generated on the fly. + // This interface is not recommended for use with emulators which have highly synchronous audio. + // + // The callback only notifies about writability; the libretro core still has to call the normal audio callbacks + // to write audio. The audio callbacks must be called from within the notification callback. + // The amount of audio data to write is up to the implementation. + // Generally, the audio callback will be called continously in a loop. + // + // Due to thread safety guarantees and lack of sync between audio and video, a frontend + // can selectively disallow this interface based on internal configuration. A core using + // this interface must also implement the "normal" audio interface. + // + // A libretro core using SET_AUDIO_CALLBACK should also make use of SET_FRAME_TIME_CALLBACK. +#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 + // const struct retro_frame_time_callback * -- + // Lets the core know how much time has passed since last invocation of retro_run(). + // The frontend can tamper with the timing to fake fast-forward, slow-motion, frame stepping, etc. + // In this case the delta time will use the reference value in frame_time_callback.. + // +#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 + // struct retro_rumble_interface * -- + // Gets an interface which is used by a libretro core to set state of rumble motors in controllers. + // A strong and weak motor is supported, and they can be controlled indepedently. + // +#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 + // uint64_t * -- + // Gets a bitmask telling which device type are expected to be handled properly in a call to retro_input_state_t. + // Devices which are not handled or recognized always return 0 in retro_input_state_t. + // Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG). + // Should only be called in retro_run(). + // +#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL) + // struct retro_sensor_interface * -- + // Gets access to the sensor interface. + // The purpose of this interface is to allow + // setting state related to sensors such as polling rate, enabling/disable it entirely, etc. + // Reading sensor state is done via the normal input_state_callback API. + // +#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL) + // struct retro_camera_callback * -- + // Gets an interface to a video camera driver. + // A libretro core can use this interface to get access to a video camera. + // New video frames are delivered in a callback in same thread as retro_run(). + // + // GET_CAMERA_INTERFACE should be called in retro_load_game(). + // + // Depending on the camera implementation used, camera frames will be delivered as a raw framebuffer, + // or as an OpenGL texture directly. + // + // The core has to tell the frontend here which types of buffers can be handled properly. + // An OpenGL texture can only be handled when using a libretro GL core (SET_HW_RENDER). + // It is recommended to use a libretro GL core when using camera interface. + // + // The camera is not started automatically. The retrieved start/stop functions must be used to explicitly + // start and stop the camera driver. + // +#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27 + // struct retro_log_callback * -- + // Gets an interface for logging. This is useful for logging in a cross-platform way + // as certain platforms cannot use use stderr for logging. It also allows the frontend to + // show logging information in a more suitable way. + // If this interface is not used, libretro cores should log to stderr as desired. + +enum retro_log_level +{ + RETRO_LOG_DEBUG = 0, + RETRO_LOG_INFO, + RETRO_LOG_WARN, + RETRO_LOG_ERROR, + + RETRO_LOG_DUMMY = INT_MAX +}; + +// Logging function. Takes log level argument as well. +typedef void (*retro_log_printf_t)(enum retro_log_level level, const char *fmt, ...); + +struct retro_log_callback +{ + retro_log_printf_t log; +}; + +// FIXME: Document the sensor API and work out behavior. +// It will be marked as experimental until then. +enum retro_sensor_action +{ + RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, + RETRO_SENSOR_ACCELEROMETER_DISABLE, + + RETRO_SENSOR_DUMMY = INT_MAX +}; + +typedef bool (*retro_set_sensor_state_t)(unsigned port, enum retro_sensor_action action, unsigned rate); +struct retro_sensor_interface +{ + retro_set_sensor_state_t set_sensor_state; +}; +//// + +enum retro_camera_buffer +{ + RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0, + RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER, + + RETRO_CAMERA_BUFFER_DUMMY = INT_MAX +}; + +// Starts the camera driver. Can only be called in retro_run(). +typedef bool (*retro_camera_start_t)(void); +// Stops the camera driver. Can only be called in retro_run(). +typedef void (*retro_camera_stop_t)(void); +// Callback which signals when the camera driver is initialized and/or deinitialized. +// retro_camera_start_t can be called in initialized callback. +typedef void (*retro_camera_lifetime_status_t)(void); +// A callback for raw framebuffer data. buffer points to an XRGB8888 buffer. +// Width, height and pitch are similar to retro_video_refresh_t. +// First pixel is top-left origin. +typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer, unsigned width, unsigned height, size_t pitch); +// A callback for when OpenGL textures are used. +// +// texture_id is a texture owned by camera driver. +// Its state or content should be considered immutable, except for things like texture filtering and clamping. +// +// texture_target is the texture target for the GL texture. +// These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly more depending on extensions. +// +// affine points to a packed 3x3 column-major matrix used to apply an affine transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0)) +// After transform, normalized texture coord (0, 0) should be bottom-left and (1, 1) should be top-right (or (width, height) for RECTANGLE). +// +// GL-specific typedefs are avoided here to avoid relying on gl.h in the API definition. +typedef void (*retro_camera_frame_opengl_texture_t)(unsigned texture_id, unsigned texture_target, const float *affine); +struct retro_camera_callback +{ + uint64_t caps; // Set by libretro core. Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER). + + unsigned width; // Desired resolution for camera. Is only used as a hint. + unsigned height; + retro_camera_start_t start; // Set by frontend. + retro_camera_stop_t stop; // Set by frontend. + + retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer; // Set by libretro core if raw framebuffer callbacks will be used. + retro_camera_frame_opengl_texture_t frame_opengl_texture; // Set by libretro core if OpenGL texture callbacks will be used. + + // Set by libretro core. Called after camera driver is initialized and ready to be started. + // Can be NULL, in which this callback is not called. + retro_camera_lifetime_status_t initialized; + + // Set by libretro core. Called right before camera driver is deinitialized. + // Can be NULL, in which this callback is not called. + retro_camera_lifetime_status_t deinitialized; +}; + +enum retro_rumble_effect +{ + RETRO_RUMBLE_STRONG = 0, + RETRO_RUMBLE_WEAK = 1, + + RETRO_RUMBLE_DUMMY = INT_MAX +}; + +// Sets rumble state for joypad plugged in port 'port'. Rumble effects are controlled independently, +// and setting e.g. strong rumble does not override weak rumble. +// Strength has a range of [0, 0xffff]. +// +// Returns true if rumble state request was honored. Calling this before first retro_run() is likely to return false. +typedef bool (*retro_set_rumble_state_t)(unsigned port, enum retro_rumble_effect effect, uint16_t strength); +struct retro_rumble_interface +{ + retro_set_rumble_state_t set_rumble_state; +}; + +// Notifies libretro that audio data should be written. +typedef void (*retro_audio_callback_t)(void); + +// True: Audio driver in frontend is active, and callback is expected to be called regularily. +// False: Audio driver in frontend is paused or inactive. Audio callback will not be called until set_state has been called with true. +// Initial state is false (inactive). +typedef void (*retro_audio_set_state_callback_t)(bool enabled); +struct retro_audio_callback +{ + retro_audio_callback_t callback; + retro_audio_set_state_callback_t set_state; +}; + +// Notifies a libretro core of time spent since last invocation of retro_run() in microseconds. +// It will be called right before retro_run() every frame. +// The frontend can tamper with timing to support cases like fast-forward, slow-motion and framestepping. +// In those scenarios the reference frame time value will be used. +typedef int64_t retro_usec_t; +typedef void (*retro_frame_time_callback_t)(retro_usec_t usec); +struct retro_frame_time_callback +{ + retro_frame_time_callback_t callback; + retro_usec_t reference; // Represents the time of one frame. It is computed as 1000000 / fps, but the implementation will resolve the rounding to ensure that framestepping, etc is exact. +}; // Pass this to retro_video_refresh_t if rendering to hardware. // Passing NULL to retro_video_refresh_t is still a frame dupe as normal. #define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1) // Invalidates the current HW context. +// Any GL state is lost, and must not be deinitialized explicitly. If explicit deinitialization is desired by the libretro core, +// it should implement context_destroy callback. // If called, all GPU resources must be reinitialized. // Usually called when frontend reinits video driver. // Also called first time video driver is initialized, allowing libretro core to init resources. @@ -472,8 +718,10 @@ typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym); enum retro_hw_context_type { RETRO_HW_CONTEXT_NONE = 0, - RETRO_HW_CONTEXT_OPENGL, // OpenGL 2.x. Latest version available before 3.x+. + RETRO_HW_CONTEXT_OPENGL, // OpenGL 2.x. Latest version available before 3.x+. Driver can choose to use latest compatibility context. RETRO_HW_CONTEXT_OPENGLES2, // GLES 2.0 + RETRO_HW_CONTEXT_OPENGL_CORE, // Modern desktop core GL context. Use major/minor fields to set GL version. + RETRO_HW_CONTEXT_OPENGLES3, // GLES 3.0 RETRO_HW_CONTEXT_DUMMY = INT_MAX }; @@ -481,10 +729,21 @@ enum retro_hw_context_type struct retro_hw_render_callback { enum retro_hw_context_type context_type; // Which API to use. Set by libretro core. - retro_hw_context_reset_t context_reset; // Set by libretro core. + retro_hw_context_reset_t context_reset; // Called when a context has been created or when it has been reset. retro_hw_get_current_framebuffer_t get_current_framebuffer; // Set by frontend. retro_hw_get_proc_address_t get_proc_address; // Set by frontend. bool depth; // Set if render buffers should have depth component attached. + bool stencil; // Set if stencil buffers should be attached. + // If depth and stencil are true, a packed 24/8 buffer will be added. Only attaching stencil is invalid and will be ignored. + bool bottom_left_origin; // Use conventional bottom-left origin convention. Is false, standard libretro top-left origin semantics are used. + unsigned version_major; // Major version number for core GL context. + unsigned version_minor; // Minor version number for core GL context. + + bool cache_context; // If this is true, the frontend will go very far to avoid resetting context in scenarios like toggling fullscreen, etc. + // The reset callback might still be called in extreme situations such as if the context is lost beyond recovery. + // For optimal stability, set this to false, and allow context to be reset at any time. + retro_hw_context_reset_t context_destroy; // A callback to be called before the context is destroyed. Resources can be deinitialized at this step. This can be set to NULL, in which resources will just be destroyed without any notification. + bool debug_context; // Creates a debug context. }; // Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events. @@ -492,11 +751,18 @@ struct retro_hw_render_callback // keycode is the RETROK value of the char. // character is the text character of the pressed key. (UTF-32). // key_modifiers is a set of RETROKMOD values or'ed together. +// +// The pressed/keycode state can be indepedent of the character. +// It is also possible that multiple characters are generated from a single keypress. +// Keycode events should be treated separately from character events. +// However, when possible, the frontend should try to synchronize these. +// If only a character is posted, keycode should be RETROK_UNKNOWN. +// Similarily if only a keycode event is generated with no corresponding character, character should be 0. typedef void (*retro_keyboard_event_t)(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); struct retro_keyboard_callback { - retro_keyboard_event_t callback; + retro_keyboard_event_t callback; }; // Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. From 1c95cbb498d9f04cc12d0340ffda27b33fae870f Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 16 Dec 2013 12:50:46 +0100 Subject: [PATCH 39/39] Check if log_cb is not null before using log_cb callback --- libretro/libretro.c | 49 +++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/libretro/libretro.c b/libretro/libretro.c index 7d12896..edc978e 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -73,7 +73,8 @@ static retro_audio_sample_batch_t audio_cb; void error(char * msg, ...) { - log_cb(RETRO_LOG_ERROR, msg); + if (log_cb) + log_cb(RETRO_LOG_ERROR, msg); } int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension) @@ -94,11 +95,13 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten /* Mega CD BIOS are required files */ if (!strcmp(filename,CD_BIOS_US) || !strcmp(filename,CD_BIOS_EU) || !strcmp(filename,CD_BIOS_JP)) { - log_cb(RETRO_LOG_ERROR, "Unable to open CD BIOS: %s.\n", filename); + if (log_cb) + log_cb(RETRO_LOG_ERROR, "Unable to open CD BIOS: %s.\n", filename); return 0; } - log_cb(RETRO_LOG_ERROR, "Unable to open file.\n"); + if (log_cb) + log_cb(RETRO_LOG_ERROR, "Unable to open file.\n"); return 0; } @@ -110,11 +113,13 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten if(size > maxsize) { fclose(fd); - log_cb(RETRO_LOG_ERROR, "File is too large.\n"); + if (log_cb) + log_cb(RETRO_LOG_ERROR, "File is too large.\n"); return 0; } - log_cb(RETRO_LOG_INFO, "INFORMATION - Loading %d bytes ...\n", size); + if (log_cb) + log_cb(RETRO_LOG_INFO, "INFORMATION - Loading %d bytes ...\n", size); /* filename extension */ if (extension) @@ -853,7 +858,8 @@ bool retro_load_game(const struct retro_game_info *info) if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) || !dir) { - log_cb(RETRO_LOG_INFO, "[genplus]: Defaulting system directory to %s.\n", g_rom_dir); + if (log_cb) + log_cb(RETRO_LOG_INFO, "[genplus]: Defaulting system directory to %s.\n", g_rom_dir); dir = g_rom_dir; } @@ -868,17 +874,20 @@ bool retro_load_game(const struct retro_game_info *info) snprintf(CD_BRAM_US, sizeof(CD_BRAM_US), "%s%cscd_U.brm", dir, slash); snprintf(CD_BRAM_JP, sizeof(CD_BRAM_JP), "%s%cscd_J.brm", dir, slash); snprintf(CART_BRAM, sizeof(CART_BRAM), "%s%ccart.brm", dir, slash); - log_cb(RETRO_LOG_INFO, "Game Genie ROM should be located at: %s\n", GG_ROM); - log_cb(RETRO_LOG_INFO, "Action Replay (Pro) ROM should be located at: %s\n", AR_ROM); - log_cb(RETRO_LOG_INFO, "Sonic & Knuckles (2 MB) ROM should be located at: %s\n", SK_ROM); - log_cb(RETRO_LOG_INFO, "Sonic & Knuckles UPMEM (256 KB) ROM should be located at: %s\n", SK_UPMEM); - log_cb(RETRO_LOG_INFO, "Mega CD PAL BIOS should be located at: %s\n", CD_BIOS_EU); - log_cb(RETRO_LOG_INFO, "Sega CD NTSC-U BIOS should be located at: %s\n", CD_BIOS_US); - log_cb(RETRO_LOG_INFO, "Mega CD NTSC-J BIOS should be located at: %s\n", CD_BIOS_JP); - log_cb(RETRO_LOG_INFO, "Mega CD PAL BRAM is located at: %s\n", CD_BRAM_EU); - log_cb(RETRO_LOG_INFO, "Sega CD NTSC-U BRAM is located at: %s\n", CD_BRAM_US); - log_cb(RETRO_LOG_INFO, "Mega CD NTSC-J BRAM is located at: %s\n", CD_BRAM_JP); - log_cb(RETRO_LOG_INFO, "Mega CD RAM CART is located at: %s\n", CART_BRAM); + if (log_cb) + { + log_cb(RETRO_LOG_INFO, "Game Genie ROM should be located at: %s\n", GG_ROM); + log_cb(RETRO_LOG_INFO, "Action Replay (Pro) ROM should be located at: %s\n", AR_ROM); + log_cb(RETRO_LOG_INFO, "Sonic & Knuckles (2 MB) ROM should be located at: %s\n", SK_ROM); + log_cb(RETRO_LOG_INFO, "Sonic & Knuckles UPMEM (256 KB) ROM should be located at: %s\n", SK_UPMEM); + log_cb(RETRO_LOG_INFO, "Mega CD PAL BIOS should be located at: %s\n", CD_BIOS_EU); + log_cb(RETRO_LOG_INFO, "Sega CD NTSC-U BIOS should be located at: %s\n", CD_BIOS_US); + log_cb(RETRO_LOG_INFO, "Mega CD NTSC-J BIOS should be located at: %s\n", CD_BIOS_JP); + log_cb(RETRO_LOG_INFO, "Mega CD PAL BRAM is located at: %s\n", CD_BRAM_EU); + log_cb(RETRO_LOG_INFO, "Sega CD NTSC-U BRAM is located at: %s\n", CD_BRAM_US); + log_cb(RETRO_LOG_INFO, "Mega CD NTSC-J BRAM is located at: %s\n", CD_BRAM_JP); + log_cb(RETRO_LOG_INFO, "Mega CD RAM CART is located at: %s\n", CART_BRAM); + } check_variables(); if (!load_rom((char *)info->path)) @@ -958,12 +967,14 @@ void retro_init(void) environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level); environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log); - log_cb = log.log; + if (log.log) + log_cb = log.log; #ifdef FRONTEND_SUPPORTS_RGB565 rgb565 = RETRO_PIXEL_FORMAT_RGB565; if(environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565)) - log_cb(RETRO_LOG_INFO, "Frontend supports RGB565 - will use that instead of XRGB1555.\n"); + if (log_cb) + log_cb(RETRO_LOG_INFO, "Frontend supports RGB565 - will use that instead of XRGB1555.\n"); #endif }