diff --git a/Makefile.libretro b/Makefile.libretro index 4cc673f..b887095 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -440,8 +440,8 @@ LIBRETRO_CFLAGS += $(BPP_DEFINES) \ $(ENDIANNESS_DEFINES) \ $(PLATFORM_DEFINES) \ -D__LIBRETRO__ \ - -DM68K_ALLOW_OVERCLOCK \ - -DZ80_ALLOW_OVERCLOCK + -DM68K_OVERCLOCK_SHIFT=20 \ + -DZ80_OVERCLOCK_SHIFT=20 ifneq (,$(findstring msvc,$(platform))) LIBRETRO_CFLAGS += -DINLINE="static _inline" diff --git a/core/m68k/m68k.h b/core/m68k/m68k.h index 93bb033..0aed500 100644 --- a/core/m68k/m68k.h +++ b/core/m68k/m68k.h @@ -268,8 +268,8 @@ typedef struct uint address_space; /* Current FC code */ -#ifdef M68K_ALLOW_OVERCLOCK - uint8 overclock_ratio; +#ifdef M68K_OVERCLOCK_SHIFT + int cycle_ratio; #endif /* Callbacks to host */ diff --git a/core/m68k/m68kcpu.c b/core/m68k/m68kcpu.c index 245bef9..37020bd 100644 --- a/core/m68k/m68kcpu.c +++ b/core/m68k/m68kcpu.c @@ -319,8 +319,8 @@ void m68k_init(void) } #endif -#ifdef M68K_ALLOW_OVERCLOCK - m68k.overclock_ratio = 1; +#ifdef M68K_OVERCLOCK_SHIFT + m68k.cycle_ratio = 1 << M68K_OVERCLOCK_SHIFT; #endif #if M68K_EMULATE_INT_ACK == OPT_ON diff --git a/core/m68k/m68kcpu.h b/core/m68k/m68kcpu.h index 8b3355e..bd4f63f 100644 --- a/core/m68k/m68kcpu.h +++ b/core/m68k/m68kcpu.h @@ -514,8 +514,8 @@ /* ---------------------------- Cycle Counting ---------------------------- */ -#ifdef M68K_ALLOW_OVERCLOCK -#define USE_CYCLES(A) m68ki_cpu.cycles += (A) / m68ki_cpu.overclock_ratio +#ifdef M68K_OVERCLOCK_SHIFT +#define USE_CYCLES(A) m68ki_cpu.cycles += ((A) * m68ki_cpu.cycle_ratio) >> M68K_OVERCLOCK_SHIFT #else #define USE_CYCLES(A) m68ki_cpu.cycles += (A) #endif diff --git a/core/m68k/s68kcpu.c b/core/m68k/s68kcpu.c index 9665085..74bd04c 100644 --- a/core/m68k/s68kcpu.c +++ b/core/m68k/s68kcpu.c @@ -284,8 +284,8 @@ void s68k_init(void) } #endif -#ifdef M68K_ALLOW_OVERCLOCK - s68k.overclock_ratio = 1; +#ifdef M68K_OVERCLOCK_SHIFT + s68k.cycle_ratio = 1 << M68K_OVERCLOCK_SHIFT; #endif #if M68K_EMULATE_INT_ACK == OPT_ON diff --git a/core/vdp_render.c b/core/vdp_render.c index c4a1876..6b65e22 100644 --- a/core/vdp_render.c +++ b/core/vdp_render.c @@ -43,6 +43,14 @@ #include "md_ntsc.h" #include "sms_ntsc.h" +#ifndef HAVE_NO_SPRITE_LIMIT +#define MAX_SPRITES_PER_LINE 20 +#define TMS_MAX_SPRITES_PER_LINE 4 +#define MODE4_MAX_SPRITES_PER_LINE 8 +#define MODE5_MAX_SPRITES_PER_LINE (bitmap.viewport.w >> 4) +#define MODE5_MAX_SPRITE_PIXELS max_sprite_pixels +#endif + /*** NTSC Filters ***/ extern md_ntsc_t *md_ntsc; extern sms_ntsc_t *sms_ntsc; @@ -584,7 +592,7 @@ typedef struct uint16 size; } object_info_t; -static object_info_t obj_info[2][20]; +static object_info_t obj_info[2][MAX_SPRITES_PER_LINE]; /* Sprite Counter */ static uint8 object_count[2]; @@ -3149,6 +3157,7 @@ void render_obj_m5(int line) int xpos, width; int pixelcount = 0; int masked = 0; + int max_pixels = MODE5_MAX_SPRITE_PIXELS; uint8 *src, *s, *lb; uint32 temp, v_line; @@ -3213,10 +3222,10 @@ void render_obj_m5(int line) lb = &linebuf[0][0x20 + xpos]; /* Max. number of sprite pixels rendered per line */ - if (pixelcount > max_sprite_pixels) + if (pixelcount > max_pixels) { /* Adjust number of pixels to draw */ - width -= (pixelcount - max_sprite_pixels); + width -= (pixelcount - max_pixels); } /* Number of tiles to draw */ @@ -3235,7 +3244,7 @@ void render_obj_m5(int line) } /* Sprite limit */ - if (pixelcount >= max_sprite_pixels) + if (pixelcount >= max_pixels) { /* Sprite masking is effective on next line if max pixel width is reached */ spr_ovr = (pixelcount >= bitmap.viewport.w); @@ -3258,6 +3267,7 @@ void render_obj_m5_ste(int line) int xpos, width; int pixelcount = 0; int masked = 0; + int max_pixels = MODE5_MAX_SPRITE_PIXELS; uint8 *src, *s, *lb; uint32 temp, v_line; @@ -3325,9 +3335,9 @@ void render_obj_m5_ste(int line) lb = &linebuf[1][0x20 + xpos]; /* Adjust number of pixels to draw for sprite limit */ - if (pixelcount > max_sprite_pixels) + if (pixelcount > max_pixels) { - width -= (pixelcount - max_sprite_pixels); + width -= (pixelcount - max_pixels); } /* Number of tiles to draw */ @@ -3346,7 +3356,7 @@ void render_obj_m5_ste(int line) } /* Sprite limit */ - if (pixelcount >= max_sprite_pixels) + if (pixelcount >= max_pixels) { /* Sprite masking is effective on next line if max pixel width is reached */ spr_ovr = (pixelcount >= bitmap.viewport.w); @@ -3376,6 +3386,7 @@ void render_obj_m5_im2(int line) int pixelcount = 0; int masked = 0; int odd = odd_frame; + int max_pixels = MODE5_MAX_SPRITE_PIXELS; uint8 *src, *s, *lb; uint32 temp, v_line; @@ -3440,9 +3451,9 @@ void render_obj_m5_im2(int line) lb = &linebuf[0][0x20 + xpos]; /* Adjust width for sprite limit */ - if (pixelcount > max_sprite_pixels) + if (pixelcount > max_pixels) { - width -= (pixelcount - max_sprite_pixels); + width -= (pixelcount - max_pixels); } /* Number of tiles to draw */ @@ -3461,7 +3472,7 @@ void render_obj_m5_im2(int line) } /* Sprite Limit */ - if (pixelcount >= max_sprite_pixels) + if (pixelcount >= max_pixels) { /* Sprite masking is effective on next line if max pixel width is reached */ spr_ovr = (pixelcount >= bitmap.viewport.w); @@ -3485,6 +3496,7 @@ void render_obj_m5_im2_ste(int line) int pixelcount = 0; int masked = 0; int odd = odd_frame; + int max_pixels = MODE5_MAX_SPRITE_PIXELS; uint8 *src, *s, *lb; uint32 temp, v_line; @@ -3552,9 +3564,9 @@ void render_obj_m5_im2_ste(int line) lb = &linebuf[1][0x20 + xpos]; /* Adjust width for sprite limit */ - if (pixelcount > max_sprite_pixels) + if (pixelcount > max_pixels) { - width -= (pixelcount - max_sprite_pixels); + width -= (pixelcount - max_pixels); } /* Number of tiles to draw */ @@ -3573,7 +3585,7 @@ void render_obj_m5_im2_ste(int line) } /* Sprite Limit */ - if (pixelcount >= max_sprite_pixels) + if (pixelcount >= max_pixels) { /* Sprite masking is effective on next line if max pixel width is reached */ spr_ovr = (pixelcount >= bitmap.viewport.w); @@ -3654,7 +3666,7 @@ void parse_satb_tms(int line) if ((ypos >= 0) && (ypos < height)) { /* Sprite overflow */ - if (count == 4) + if (count == TMS_MAX_SPRITES_PER_LINE) { /* Flag is set only during active area */ if (line < bitmap.viewport.h) @@ -3750,7 +3762,7 @@ void parse_satb_m4(int line) if ((ypos >= 0) && (ypos < height)) { /* Sprite overflow */ - if (count == 8) + if (count == MODE4_MAX_SPRITES_PER_LINE) { /* Flag is set only during active area */ if ((line >= 0) && (line < bitmap.viewport.h)) @@ -3796,7 +3808,7 @@ void parse_satb_m5(int line) int count = 0; /* max. number of rendered sprites (16 or 20 sprites per line by default) */ - int max = bitmap.viewport.w >> 4; + int max = MODE5_MAX_SPRITES_PER_LINE; /* max. number of parsed sprites (64 or 80 sprites per line by default) */ int total = max_sprite_pixels >> 2; diff --git a/core/z80/z80.c b/core/z80/z80.c index 59d7f4f..9a1280b 100644 --- a/core/z80/z80.c +++ b/core/z80/z80.c @@ -201,18 +201,15 @@ #define IFF2 Z80.iff2 #define HALT Z80.halt -#ifdef Z80_ALLOW_OVERCLOCK -#define USE_CYCLES(A) Z80.cycles += (A) / z80_overclock_ratio +#ifdef Z80_OVERCLOCK_SHIFT +#define USE_CYCLES(A) Z80.cycles += ((A) * z80_cycle_ratio) >> Z80_OVERCLOCK_SHIFT +UINT32 z80_cycle_ratio; #else #define USE_CYCLES(A) Z80.cycles += (A) #endif Z80_Regs Z80; -#ifdef Z80_ALLOW_OVERCLOCK -UINT8 z80_overclock_ratio; -#endif - unsigned char *z80_readmap[64]; unsigned char *z80_writemap[64]; @@ -3368,8 +3365,8 @@ void z80_init(const void *config, int (*irqcallback)(int)) memset(&Z80, 0, sizeof(Z80)); Z80.daisy = config; Z80.irq_callback = irqcallback; -#ifdef Z80_ALLOW_OVERCLOCK - z80_overclock_ratio = 1; +#ifdef Z80_OVERCLOCK_SHIFT + z80_cycle_ratio = 1 << Z80_OVERCLOCK_SHIFT; #endif /* Clear registers values (NB: should be random on real hardware ?) */ diff --git a/core/z80/z80.h b/core/z80/z80.h index 8ee5f6b..a85f106 100644 --- a/core/z80/z80.h +++ b/core/z80/z80.h @@ -51,8 +51,8 @@ typedef struct extern Z80_Regs Z80; -#ifdef Z80_ALLOW_OVERCLOCK -extern UINT8 z80_overclock_ratio; +#ifdef Z80_OVERCLOCK_SHIFT +extern UINT32 z80_cycle_ratio; #endif extern unsigned char *z80_readmap[64]; diff --git a/libretro/libretro.c b/libretro/libretro.c index c68ea21..ad07527 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -54,12 +54,6 @@ #include #endif -#if defined(M68K_ALLOW_OVERCLOCK) || defined(Z80_ALLOW_OVERCLOCK) -#define HAVE_OVERCLOCK -/* Overclocking frame delay (hack) */ -#define OVERCLOCK_FRAME_DELAY 100 -#endif - #define RETRO_DEVICE_MDPAD_3B RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0) #define RETRO_DEVICE_MDPAD_6B RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1) #define RETRO_DEVICE_MSPAD_2B RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 2) @@ -82,6 +76,25 @@ #include "sms_ntsc.h" #include +#define STATIC_ASSERT(name, test) typedef struct { int assert_[(test)?1:-1]; } assert_ ## name ## _ +#define M68K_MAX_CYCLES 1107 +#define Z80_MAX_CYCLES 345 +#define OVERCLOCK_FRAME_DELAY 100 + +#ifdef M68K_OVERCLOCK_SHIFT +#define HAVE_OVERCLOCK +STATIC_ASSERT(m68k_overflow, + M68K_MAX_CYCLES <= UINT_MAX >> (M68K_OVERCLOCK_SHIFT + 1)); +#endif + +#ifdef Z80_OVERCLOCK_SHIFT +#ifndef HAVE_OVERCLOCK +#define HAVE_OVERCLOCK +#endif +STATIC_ASSERT(z80_overflow, + Z80_MAX_CYCLES <= UINT_MAX >> (Z80_OVERCLOCK_SHIFT + 1)); +#endif + sms_ntsc_t *sms_ntsc; md_ntsc_t *md_ntsc; @@ -541,8 +554,9 @@ static void config_default(void) config.lock_on = 0; config.lcd = 0; /* 0.8 fixed point */ #ifdef HAVE_OVERCLOCK - config.overclock = 0; + config.overclock = 100; #endif + config.no_sprite_limit = 0; /* video options */ config.overscan = 0; @@ -811,6 +825,31 @@ static bool update_viewport(void) return ((ow != vwidth) || (oh != vheight) || (oar != vaspect_ratio)); } +#ifdef HAVE_OVERCLOCK +static void update_overclock(void) +{ +#ifdef M68K_OVERCLOCK_SHIFT + m68k.cycle_ratio = 1 << M68K_OVERCLOCK_SHIFT; +#endif +#ifdef Z80_OVERCLOCK_SHIFT + z80_cycle_ratio = 1 << Z80_OVERCLOCK_SHIFT; +#endif + if (overclock_delay == 0) + { + /* Cycle ratios multiply per-instruction cycle counts, so use + reciprocals */ +#ifdef M68K_OVERCLOCK_SHIFT + if ((system_hw & SYSTEM_PBC) == SYSTEM_MD) + m68k.cycle_ratio = (100 << M68K_OVERCLOCK_SHIFT) / config.overclock; +#endif +#ifdef Z80_OVERCLOCK_SHIFT + if ((system_hw & SYSTEM_PBC) != SYSTEM_MD) + z80_cycle_ratio = (100 << Z80_OVERCLOCK_SHIFT) / config.overclock; +#endif + } +} +#endif + static void check_variables(void) { unsigned orig_value; @@ -1270,13 +1309,31 @@ static void check_variables(void) var.key = "genesis_plus_gx_overclock"; environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); { - if (strcmp(var.value, "1x") == 0) - config.overclock = 0; - else if (strcmp(var.value, "2x") == 0) - config.overclock = 1; + if (strcmp(var.value, "100%") == 0) + config.overclock = 100; + else if (strcmp(var.value, "125%") == 0) + config.overclock = 125; + else if (strcmp(var.value, "150%") == 0) + config.overclock = 150; + else if (strcmp(var.value, "175%") == 0) + config.overclock = 175; + else if (strcmp(var.value, "200%") == 0) + config.overclock = 200; + + if (system_hw) + update_overclock(); } #endif + var.key = "genesis_plus_gx_no_sprite_limit"; + environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); + { + if (strcmp(var.value, "disabled") == 0) + config.no_sprite_limit = 0; + else + config.no_sprite_limit = 1; + } + if (reinit) { #ifdef HAVE_OVERCLOCK @@ -1722,8 +1779,9 @@ void retro_set_environment(retro_environment_t cb) { "genesis_plus_gx_gun_cursor", "Show Lightgun crosshair; disabled|enabled" }, { "genesis_plus_gx_invert_mouse", "Invert Mouse Y-axis; disabled|enabled" }, #ifdef HAVE_OVERCLOCK - { "genesis_plus_gx_overclock", "Overclock CPU; 1x|2x" }, + { "genesis_plus_gx_overclock", "CPU speed; 100%|125%|150%|175%|200%" }, #endif + { "genesis_plus_gx_no_sprite_limit", "Remove per-line sprite limit; disabled|enabled" }, { NULL, NULL }, }; @@ -2069,6 +2127,7 @@ bool retro_unserialize(const void *data, size_t size) #ifdef HAVE_OVERCLOCK overclock_delay = OVERCLOCK_FRAME_DELAY; + update_overclock(); #endif return TRUE; @@ -2235,9 +2294,6 @@ bool retro_load_game(const struct retro_game_info *info) } } -#ifdef HAVE_OVERCLOCK - overclock_delay = OVERCLOCK_FRAME_DELAY; -#endif audio_init(SOUND_FREQUENCY, 0); system_init(); system_reset(); @@ -2248,6 +2304,11 @@ bool retro_load_game(const struct retro_game_info *info) update_viewport(); +#ifdef HAVE_OVERCLOCK + overclock_delay = OVERCLOCK_FRAME_DELAY; + update_overclock(); +#endif + return true; } @@ -2355,6 +2416,7 @@ void retro_reset(void) { #ifdef HAVE_OVERCLOCK overclock_delay = OVERCLOCK_FRAME_DELAY; + update_overclock(); #endif gen_reset(0); } @@ -2366,38 +2428,20 @@ void retro_run(void) #ifdef HAVE_OVERCLOCK /* update overclock delay */ - if (overclock_delay) - overclock_delay--; + if (overclock_delay && --overclock_delay == 0) + update_overclock(); #endif if (system_hw == SYSTEM_MCD) { -#ifdef M68K_ALLOW_OVERCLOCK - if (config.overclock && overclock_delay == 0) - m68k.overclock_ratio = 2; - else - m68k.overclock_ratio = 1; -#endif system_frame_scd(0); } else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD) { -#ifdef M68K_ALLOW_OVERCLOCK - if (config.overclock && overclock_delay == 0) - m68k.overclock_ratio = 2; - else - m68k.overclock_ratio = 1; -#endif system_frame_gen(0); } else { -#ifdef Z80_ALLOW_OVERCLOCK - if (config.overclock && overclock_delay == 0) - z80_overclock_ratio = 2; - else - z80_overclock_ratio = 1; -#endif system_frame_sms(0); } diff --git a/libretro/osd.h b/libretro/osd.h index 089bb90..f895d8b 100644 --- a/libretro/osd.h +++ b/libretro/osd.h @@ -76,7 +76,14 @@ typedef unsigned char bool; #define HAVE_YM3438_CORE -typedef struct +#define HAVE_NO_SPRITE_LIMIT +#define MAX_SPRITES_PER_LINE 80 +#define TMS_MAX_SPRITES_PER_LINE (config.no_sprite_limit ? MAX_SPRITES_PER_LINE : 4) +#define MODE4_MAX_SPRITES_PER_LINE (config.no_sprite_limit ? MAX_SPRITES_PER_LINE : 8) +#define MODE5_MAX_SPRITES_PER_LINE (config.no_sprite_limit ? MAX_SPRITES_PER_LINE : (bitmap.viewport.w >> 4)) +#define MODE5_MAX_SPRITE_PIXELS (config.no_sprite_limit ? MAX_SPRITES_PER_LINE * 32 : max_sprite_pixels) + +typedef struct { int8 device; uint8 port; @@ -120,7 +127,8 @@ struct t_input_config input[MAX_INPUTS]; uint8 invert_mouse; uint8 gun_cursor; - uint8 overclock; + uint32 overclock; + uint8 no_sprite_limit; } config; extern char GG_ROM[256];