[Wii/Gamecube]

* added an option to set VDP mode (PAL/NTSC) independently from console region.
* added an option to select console master clock frequency (PAL/NTSC/AUTO): emulation now run at selected frequency when VSYNC is disabled.
* added an option to force VSYNC disabled.
* improved screen scaling.

[Core]
* moved INLINE definition to macros.h
* removed unused typedef from osd_cpu.h
* cleanup include files
This commit is contained in:
ekeeke31 2012-01-31 22:50:54 +00:00
parent 96452ac75b
commit cab4ecba99
34 changed files with 563 additions and 335 deletions

View File

@ -228,7 +228,7 @@ void md_eeprom_write_word(unsigned int address, unsigned int data)
}
static __inline__ void Detect_START()
INLINE void Detect_START()
{
if (md_eeprom.old_scl && md_eeprom.scl)
{
@ -246,7 +246,7 @@ static __inline__ void Detect_START()
}
}
static __inline__ void Detect_STOP()
INLINE void Detect_STOP()
{
if (md_eeprom.old_scl && md_eeprom.scl)
{

View File

@ -107,6 +107,8 @@ void config_default(void)
/* system options */
config.system = 0; /* AUTO */
config.region_detect = 0; /* AUTO */
config.vdp_mode = 0; /* AUTO */
config.master_clock = 0; /* AUTO */
config.force_dtack = 0;
config.addr_error = 1;
config.bios = 0;
@ -121,6 +123,8 @@ void config_default(void)
config.aspect = 1;
config.overscan = 3; /* FULL */
config.ntsc = 0;
config.vsync = 1; /* AUTO */
if (VIDEO_HaveComponentCable())
{
config.render = 2;
@ -132,6 +136,21 @@ void config_default(void)
config.bilinear = 0;
}
switch (vmode->viTVMode >> 2)
{
case VI_PAL:
config.tv_mode = 1; /* 50hz only */
break;
case VI_EURGB60:
config.tv_mode = 2; /* 50/60hz */
break;
default:
config.tv_mode = 0; /* 60hz only */
break;
}
#ifdef HW_RVL
config.trap = 0;
config.gamma = VI_GM_1_0 / 10.0;

View File

@ -65,6 +65,8 @@ typedef struct
float rolloff;
uint8 system;
uint8 region_detect;
uint8 master_clock;
uint8 vdp_mode;
uint8 force_dtack;
uint8 addr_error;
uint8 tmss;
@ -75,6 +77,7 @@ typedef struct
uint8 gun_cursor[2];
uint8 overscan;
uint8 ntsc;
uint8 vsync;
uint8 render;
uint8 tv_mode;
uint8 bilinear;

View File

@ -349,27 +349,30 @@ static gui_item items_audio[13] =
};
/* System options */
static gui_item items_system[8] =
static gui_item items_system[10] =
{
{NULL,NULL,"Console Hardware: AUTO", "Select system hardware model", 56,132,276,48},
{NULL,NULL,"Console Region: AUTO", "Select system region", 56,132,276,48},
{NULL,NULL,"System Boot: BIOS&CART", "Select system booting method", 56,132,276,48},
{NULL,NULL,"System Lockups: ON", "Enable/disable original system lock-ups", 56,132,276,48},
{NULL,NULL,"68k Address Error: ON", "Enable/disable 68k address error exceptions", 56,132,276,48},
{NULL,NULL,"Lock-on: OFF", "Select Lock-On cartridge type", 56,132,276,48},
{NULL,NULL,"Cartridge Swap: OFF", "Enable/disable cartridge hot swap", 56,132,276,48},
{NULL,NULL,"SVP Cycles: 1500", "Adjust SVP chip emulation speed", 56,132,276,48}
{NULL,NULL,"Console Hardware: AUTO", "Select system hardware model", 56,132,276,48},
{NULL,NULL,"Console Region: AUTO", "Select system region", 56,132,276,48},
{NULL,NULL,"VDP Mode: AUTO", "Select VDP mode", 56,132,276,48},
{NULL,NULL,"System Clock: AUTO", "Select system clock frequency", 56,132,276,48},
{NULL,NULL,"System Boot: BIOS&CART", "Select system booting method", 56,132,276,48},
{NULL,NULL,"System Lockups: ON", "Enable/disable original system lock-ups", 56,132,276,48},
{NULL,NULL,"68k Address Error: ON", "Enable/disable 68k address error exceptions", 56,132,276,48},
{NULL,NULL,"Lock-on: OFF", "Select Lock-On cartridge type", 56,132,276,48},
{NULL,NULL,"Cartridge Swap: OFF", "Enable/disable cartridge hot swap", 56,132,276,48},
{NULL,NULL,"SVP Cycles: 1500", "Adjust SVP chip emulation speed", 56,132,276,48}
};
/* Video options */
#ifdef HW_RVL
static gui_item items_video[10] =
static gui_item items_video[11] =
#else
static gui_item items_video[8] =
static gui_item items_video[9] =
#endif
{
{NULL,NULL,"Display: PROGRESSIVE", "Select video mode", 56,132,276,48},
{NULL,NULL,"TV mode: 50/60Hz", "Select video refresh rate", 56,132,276,48},
{NULL,NULL,"VSYNC: AUTO", "Enable/disable synchronization with Video Hardware", 56,132,276,48},
{NULL,NULL,"GX Bilinear Filter: OFF", "Enable/disable texture hardware filtering", 56,132,276,48},
#ifdef HW_RVL
{NULL,NULL,"VI Trap Filter: ON", "Enable/disable video hardware filtering", 56,132,276,48},
@ -559,7 +562,7 @@ static gui_menu menu_system =
{
"System Settings",
0,0,
8,4,6,0,
10,4,6,0,
items_system,
buttons_list,
bg_list,
@ -573,7 +576,7 @@ static gui_menu menu_video =
{
"Video Settings",
0,0,
8,4,6,0,
9,4,6,0,
items_video,
buttons_list,
bg_list,
@ -1063,6 +1066,7 @@ static const uint16 vc_table[4][2] =
static void systemmenu ()
{
int ret, quit = 0;
int reinit = 0;
gui_menu *m = &menu_system;
gui_item *items = m->items;
@ -1090,29 +1094,43 @@ static void systemmenu ()
else if (config.region_detect == 3)
sprintf (items[1].text, "Console Region: JAPAN");
sprintf (items[2].text, "System Boot: %s", (config.bios & 1) ? ((config.bios & 2) ? "BIOS&CART" : "BIOS ONLY") : "CART");
sprintf (items[3].text, "System Lockups: %s", config.force_dtack ? "OFF" : "ON");
sprintf (items[4].text, "68k Address Error: %s", config.addr_error ? "ON" : "OFF");
if (config.vdp_mode == 0)
sprintf (items[2].text, "VDP Mode: AUTO");
else if (config.vdp_mode == 1)
sprintf (items[2].text, "VDP Mode: NTSC");
else if (config.vdp_mode == 2)
sprintf (items[2].text, "VDP Mode: PAL");
if (config.master_clock == 0)
sprintf (items[3].text, "System Clock: AUTO");
else if (config.master_clock == 1)
sprintf (items[3].text, "System Clock: NTSC");
else if (config.master_clock == 2)
sprintf (items[3].text, "System Clock: PAL");
sprintf (items[4].text, "System Boot: %s", (config.bios & 1) ? ((config.bios & 2) ? "BIOS&CART" : "BIOS ONLY") : "CART");
sprintf (items[5].text, "System Lockups: %s", config.force_dtack ? "OFF" : "ON");
sprintf (items[6].text, "68k Address Error: %s", config.addr_error ? "ON" : "OFF");
if (config.lock_on == TYPE_GG)
sprintf (items[5].text, "Lock-On: GAME GENIE");
sprintf (items[7].text, "Lock-On: GAME GENIE");
else if (config.lock_on == TYPE_AR)
sprintf (items[5].text, "Lock-On: ACTION REPLAY");
sprintf (items[7].text, "Lock-On: ACTION REPLAY");
else if (config.lock_on == TYPE_SK)
sprintf (items[5].text, "Lock-On: SONIC&KNUCKLES");
sprintf (items[7].text, "Lock-On: SONIC&KNUCKLES");
else
sprintf (items[5].text, "Lock-On: OFF");
sprintf (items[7].text, "Lock-On: OFF");
sprintf (items[6].text, "Cartridge Swap: %s", config.hot_swap ? "ON":"OFF");
sprintf (items[8].text, "Cartridge Swap: %s", config.hot_swap ? "ON":"OFF");
if (svp)
{
sprintf (items[7].text, "SVP Cycles: %d", SVP_cycles);
m->max_items = 8;
sprintf (items[9].text, "SVP Cycles: %d", SVP_cycles);
m->max_items = 10;
}
else
{
m->max_items = 7;
m->max_items = 9;
}
GUI_InitMenu(m);
@ -1138,32 +1156,24 @@ static void systemmenu ()
{
config.system = SYSTEM_SG;
sprintf (items[0].text, "Console Hardware: SG-1000");
/* Force system hardware */
system_hw = SYSTEM_SG;
}
else if (config.system == SYSTEM_SG)
{
config.system = SYSTEM_MARKIII;
sprintf (items[0].text, "Console Hardware: MARK-III");
/* Force system hardware */
system_hw = SYSTEM_MARKIII;
}
else if (config.system == SYSTEM_MARKIII)
{
config.system = SYSTEM_SMS;
sprintf (items[0].text, "Console Hardware: SMS");
/* Force system hardware */
system_hw = SYSTEM_SMS;
}
else if (config.system == SYSTEM_SMS)
{
config.system = SYSTEM_SMS2;
sprintf (items[0].text, "Console Hardware: SMS-II");
/* Force system hardware */
system_hw = SYSTEM_SMS2;
}
else if (config.system == SYSTEM_SMS2)
@ -1199,7 +1209,7 @@ static void systemmenu ()
}
}
/* restart emulation */
/* force hard reset */
system_init();
system_reset();
@ -1226,66 +1236,61 @@ static void systemmenu ()
if (cart.romsize)
{
/* reset console region */
region_autodetect();
if (system_hw == SYSTEM_MD)
{
io_reg[0x00] = 0x20 | region_code | (config.bios & 1);
}
else
{
io_reg[0x00] = 0x80 | (region_code >> 1);
}
/* reinitialize audio timings */
if (vdp_pal)
{
audio_init(snd.sample_rate, (config.tv_mode == 0) ? 50.0 : ((config.render || interlaced) ? 50.00 : (1000000.0/19968.0)));
}
else
{
audio_init(snd.sample_rate, (config.tv_mode == 1) ? 60.0 : ((config.render || interlaced) ? 59.94 : (1000000.0/16715.0)));
}
/* reintialize VDP */
vdp_init();
/* reintialize VDP Status flag */
if (system_hw & SYSTEM_MD)
{
status = (status & ~1) | vdp_pal;
}
/* reinitialize VC max value */
switch (bitmap.viewport.h)
{
case 192:
vc_max = vc_table[0][vdp_pal];
break;
case 224:
vc_max = vc_table[1][vdp_pal];
break;
case 240:
vc_max = vc_table[3][vdp_pal];
break;
}
/* reinitialize sound emulation */
sound_restore();
/* force system reinitialization */
reinit = 1;
}
break;
}
case 2: /*** BIOS support ***/
case 2: /*** Force VDP mode ***/
{
config.vdp_mode = (config.vdp_mode + 1) % 3;
if (config.vdp_mode == 0)
sprintf (items[2].text, "VDP Mode: AUTO");
else if (config.vdp_mode == 1)
sprintf (items[2].text, "VDP Mode: NTSC");
else if (config.vdp_mode == 2)
sprintf (items[2].text, "VDP Mode: PAL");
if (cart.romsize)
{
/* force system reinitialization */
reinit = 1;
}
break;
}
case 3: /*** Force Master Clock ***/
{
config.master_clock = (config.master_clock + 1) % 3;
if (config.master_clock == 0)
sprintf (items[3].text, "System Clock: AUTO");
else if (config.master_clock == 1)
sprintf (items[3].text, "System Clock: NTSC");
else if (config.master_clock == 2)
sprintf (items[3].text, "System Clock: PAL");
if (cart.romsize)
{
/* force system reinitialization */
reinit = 1;
}
break;
}
case 4: /*** BIOS support ***/
{
uint8 temp = config.bios & 3;
config.bios &= ~3;
if (temp == 0) config.bios |= 3;
else if (temp == 3) config.bios |= 1;
sprintf (items[2].text, "System Boot: %s", (config.bios & 1) ? ((config.bios & 2) ? "BIOS&CART " : "BIOS ONLY") : "CART");
sprintf (items[4].text, "System Boot: %s", (config.bios & 1) ? ((config.bios & 2) ? "BIOS&CART " : "BIOS ONLY") : "CART");
if (cart.romsize && ((system_hw == SYSTEM_MD) || (system_hw & SYSTEM_GG) || (system_hw & SYSTEM_SMS)))
{
/* reset emulation */
/* force hard reset */
system_init();
system_reset();
@ -1298,18 +1303,19 @@ static void systemmenu ()
break;
}
case 3: /*** force DTACK ***/
case 5: /*** force DTACK ***/
{
config.force_dtack ^= 1;
sprintf (items[3].text, "System Lockups: %s", config.force_dtack ? "OFF" : "ON");
sprintf (items[5].text, "System Lockups: %s", config.force_dtack ? "OFF" : "ON");
break;
}
case 4: /*** 68k Address Error ***/
case 6: /*** 68k Address Error ***/
{
config.addr_error ^= 1;
if (cart.romsize && ((system_hw & SYSTEM_PBC) == SYSTEM_MD))
{
/* reinitialize cartridge hardware (UMK3 hack support) */
md_cart_init();
/* restore SRAM */
@ -1318,27 +1324,25 @@ static void systemmenu ()
slot_autoload(0,config.s_device);
}
}
sprintf (items[4].text, "68k Address Error: %s", config.addr_error ? "ON" : "OFF");
sprintf (items[6].text, "68k Address Error: %s", config.addr_error ? "ON" : "OFF");
break;
}
case 5: /*** Cart Lock-On ***/
case 7: /*** Cart Lock-On ***/
{
config.lock_on++;
if (config.lock_on > TYPE_SK)
config.lock_on = 0;
config.lock_on = (config.lock_on + 1) % (TYPE_SK + 1);
if (config.lock_on == TYPE_GG)
sprintf (items[5].text, "Lock-On: GAME GENIE");
sprintf (items[7].text, "Lock-On: GAME GENIE");
else if (config.lock_on == TYPE_AR)
sprintf (items[5].text, "Lock-On: ACTION REPLAY");
sprintf (items[7].text, "Lock-On: ACTION REPLAY");
else if (config.lock_on == TYPE_SK)
sprintf (items[5].text, "Lock-On: SONIC&KNUCKLES");
sprintf (items[7].text, "Lock-On: SONIC&KNUCKLES");
else
sprintf (items[5].text, "Lock-On: OFF");
sprintf (items[7].text, "Lock-On: OFF");
if (cart.romsize && ((system_hw & SYSTEM_PBC) == SYSTEM_MD))
{
/* restart emulation */
/* force hard reset */
system_init();
system_reset();
@ -1371,17 +1375,17 @@ static void systemmenu ()
break;
}
case 6: /*** Cartridge Hot Swap ***/
case 8: /*** Cartridge Hot Swap ***/
{
config.hot_swap ^= 1;
sprintf (items[6].text, "Cartridge Swap: %s", config.hot_swap ? "ON":"OFF");
sprintf (items[8].text, "Cartridge Swap: %s", config.hot_swap ? "ON":"OFF");
break;
}
case 7: /*** SVP cycles per line ***/
case 9: /*** SVP cycles per line ***/
{
GUI_OptionBox(m,0,"SVP Cycles",(void *)&SVP_cycles,1,1,1500,1);
sprintf (items[7].text, "SVP Cycles: %d", SVP_cycles);
sprintf (items[9].text, "SVP Cycles: %d", SVP_cycles);
break;
}
@ -1393,6 +1397,54 @@ static void systemmenu ()
}
}
if (reinit)
{
/* reinitialize console region */
region_autodetect();
/* reinitialize I/O region register */
if (system_hw == SYSTEM_MD)
{
io_reg[0x00] = 0x20 | region_code | (config.bios & 1);
}
else
{
io_reg[0x00] = 0x80 | (region_code >> 1);
}
/* reinitialize VDP */
if (vdp_pal)
{
status |= 1;
lines_per_frame = 313;
}
else
{
status &= ~1;
lines_per_frame = 262;
}
/* reinitialize VC max value */
switch (bitmap.viewport.h)
{
case 192:
vc_max = vc_table[0][vdp_pal];
break;
case 224:
vc_max = vc_table[1][vdp_pal];
break;
case 240:
vc_max = vc_table[3][vdp_pal];
break;
}
/* framerate has changed, reinitialize audio timings */
audio_init(snd.sample_rate, get_framerate());
/* reinitialize sound emulation */
sound_restore();
}
GUI_DeleteMenu(m);
}
@ -1401,14 +1453,14 @@ static void systemmenu ()
*
****************************************************************************/
#ifdef HW_RVL
#define VI_OFFSET 5
#define VI_OFFSET 6
static void update_gamma(void)
{
VIDEO_SetGamma((int)(config.gamma * 10.0));
VIDEO_Flush();
}
#else
#define VI_OFFSET 3
#define VI_OFFSET 4
#endif
static void videomenu ()
@ -1433,11 +1485,16 @@ static void videomenu ()
else
sprintf (items[1].text, "TV Mode: 50/60HZ");
sprintf (items[2].text, "GX Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
if (config.vsync)
sprintf (items[2].text, "VSYNC: AUTO");
else
sprintf (items[2].text, "VSYNC: OFF");
sprintf (items[3].text, "GX Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
#ifdef HW_RVL
sprintf (items[3].text, "VI Trap Filter: %s", config.trap ? " ON" : "OFF");
sprintf (items[4].text, "VI Gamma Correction: %1.1f", config.gamma);
sprintf (items[4].text, "VI Trap Filter: %s", config.trap ? " ON" : "OFF");
sprintf (items[5].text, "VI Gamma Correction: %1.1f", config.gamma);
#endif
if (config.ntsc == 1)
@ -1531,18 +1588,27 @@ static void videomenu ()
}
break;
case 2: /*** GX Texture filtering ***/
case 2: /*** VSYNC ***/
config.vsync ^= 1;
if (config.vsync)
sprintf (items[2].text, "VSYNC: AUTO");
else
sprintf (items[2].text, "VSYNC: OFF");
reinit = 1;
break;
case 3: /*** GX Texture filtering ***/
config.bilinear ^= 1;
sprintf (items[2].text, "GX Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
sprintf (items[3].text, "GX Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
break;
#ifdef HW_RVL
case 3: /*** VIDEO Trap filtering ***/
case 4: /*** VIDEO Trap filtering ***/
config.trap ^= 1;
sprintf (items[3].text, "VI Trap Filter: %s", config.trap ? " ON" : "OFF");
sprintf (items[4].text, "VI Trap Filter: %s", config.trap ? " ON" : "OFF");
break;
case 4: /*** VIDEO Gamma correction ***/
case 5: /*** VIDEO Gamma correction ***/
if (cart.romsize)
{
update_gamma();
@ -1561,7 +1627,7 @@ static void videomenu ()
m->arrows[1]->state = state[1];
m->screenshot = 0;
strcpy(m->title,"Video Settings");
sprintf (items[4].text, "VI Gamma Correction: %1.1f", config.gamma);
sprintf (items[5].text, "VI Gamma Correction: %1.1f", config.gamma);
VIDEO_SetGamma(VI_GM_1_0);
VIDEO_Flush();
}
@ -1689,15 +1755,8 @@ static void videomenu ()
if (cart.romsize && reinit)
{
/* reinitialize audio timings */
if (vdp_pal)
{
audio_init(snd.sample_rate, (config.tv_mode == 0) ? 50.0 : ((config.render || interlaced) ? 50.00 : (1000000.0/19968.0)));
}
else
{
audio_init(snd.sample_rate, (config.tv_mode == 1) ? 60.0 : ((config.render || interlaced) ? 59.94 : (1000000.0/16715.0)));
}
/* framerate has changed, reinitialize audio timings */
audio_init(snd.sample_rate, get_framerate());
/* reinitialize sound chips */
sound_restore();

View File

@ -39,14 +39,14 @@
#include "shared.h"
/* DMA soundbuffers (required to be 32-bytes aligned)
Length is dimensionned for one frame of emulation (800/808 samples @60hz, 960 samples@50Hz)
To prevent audio clashes, we use double buffering technique:
one buffer is the active DMA buffer
the other one is the current work buffer (updated during frame emulation)
We do not need more since frame emulation and DMA operation are synchronized
*/
u8 soundbuffer[2][3840] ATTRIBUTE_ALIGN(32);
u8 soundbuffer[2][SOUND_BUFFER_MAX_SIZE] ATTRIBUTE_ALIGN(32);
/* Current work soundbuffer */
u32 mixbuffer;
@ -65,6 +65,15 @@ static u32 Bg_music_ogg_size = 0;
/* Audio DMA callback */
static void ai_callback(void)
{
#ifdef LOG_TIMING
u64 current = gettime();
if (prevtime)
{
delta_time[frame_cnt] = diff_nsec(prevtime, current);
frame_cnt = (frame_cnt + 1) % LOGSIZE;
}
prevtime = current;
#endif
frameticker ++;
}
@ -115,8 +124,18 @@ void gx_audio_Shutdown(void)
***/
void gx_audio_Update(void)
{
/* retrieve audio samples */
/* retrieve audio samples (size must be multiple of 32 bytes) */
int size = audio_update() * 4;
#ifdef LOG_TIMING
if (prevtime && (frame_cnt < LOGSIZE - 1))
{
delta_samp[frame_cnt + 1] = size;
}
else
{
delta_samp[0] = size;
}
#endif
/* set next DMA soundbuffer */
s16 *sb = (s16 *)(soundbuffer[mixbuffer]);
@ -131,10 +150,6 @@ void gx_audio_Update(void)
/* Therefore we need to make sure frame emulation is completed before current DMA is */
/* completed, either by synchronizing frame emulation with DMA start or by syncing it */
/* with Vertical Interrupt and outputing a suitable number of samples per frame. */
/* */
/* In both cases, audio DMA need to be synchronized with VSYNC and therefore need to */
/* be resynchronized (restarted) every time video settings are changed (hopefully, */
/* this generally happens while no music is played. */
if (!audioStarted)
{
/* restart audio DMA */
@ -165,14 +180,15 @@ void gx_audio_Start(void)
AUDIO_RegisterDMACallback(NULL);
DSP_Halt();
/* when TV mode does not match emulated video mode, frame emulation is synchronized with Audio Interface DMA */
if (gc_pal != vdp_pal)
/* when VSYNC is forced OFF or AUTO with TV mode not matching emulated video mode, emulation is synchronized with Audio Hardware */
if (!config.vsync || (config.tv_mode == !vdp_pal))
{
/* DMA Interrupt callback */
AUDIO_RegisterDMACallback(ai_callback);
}
/* reset emulation audio processing */
memset(soundbuffer, 0, 2 * 3840);
memset(soundbuffer, 0, 2 * SOUND_BUFFER_MAX_SIZE);
audioStarted = 0;
mixbuffer = 0;
}

View File

@ -40,7 +40,10 @@
#ifndef _GC_AUDIO_H_
#define _GC_AUDIO_H_
extern u8 soundbuffer[2][3840];
/* Length is dimensionned for at least one frame of emulation */
#define SOUND_BUFFER_MAX_SIZE 4096
extern u8 soundbuffer[2][SOUND_BUFFER_MAX_SIZE];
extern u32 mixbuffer;
extern u32 audioStarted;

View File

@ -351,6 +351,15 @@ static camera cam = {
/* VSYNC callback */
static void vi_callback(u32 cnt)
{
#ifdef LOG_TIMING
u64 current = gettime();
if (prevtime)
{
delta_time[frame_cnt] = diff_nsec(prevtime, current);
frame_cnt = (frame_cnt + 1) % LOGSIZE;
}
prevtime = current;
#endif
frameticker ++;
}
@ -467,80 +476,99 @@ static void gxResetMode(GXRModeObj *tvmode)
/* Manage Aspect Ratio */
static void gxSetAspectRatio(int *xscale, int *yscale)
{
/* original aspect ratio */
/* the following values have been deducted from comparison with a real 50/60hz Mega Drive */
/* Vertical Scaling is disabled by default */
*yscale = (bitmap.viewport.h + (2 * bitmap.viewport.y)) / 2;
/* Original aspect ratio */
if (config.aspect)
{
/* vertical borders */
if (config.overscan & 1)
/* Adjust vertical scaling when input & output video heights are different */
if (vdp_pal && (!gc_pal || config.render))
{
/* Genesis outputs 288(PAL) or 243(NTSC) lines */
/* Wii & Game Cube output 286/574(PAL50) or 240/480 (PAL60 & NTSC) lines */
*yscale = vdp_pal + ((gc_pal && !config.render) ? 143 : 120);
*yscale = *yscale * VI_MAX_HEIGHT_NTSC / VI_MAX_HEIGHT_PAL;
}
else
else if (!vdp_pal && gc_pal && !config.render)
{
/* overscan is simulated (black) */
*yscale = vheight / 2;
/* adjust when Genesis & Wii/GC video height does not match */
if (vdp_pal && (!gc_pal || config.render))
{
*yscale = *yscale * 240 / 288;
}
else if (!vdp_pal && gc_pal && !config.render)
{
*yscale = *yscale * 288 / 240;
}
*yscale = *yscale * VI_MAX_HEIGHT_PAL / VI_MAX_HEIGHT_NTSC;
}
/* horizontal borders */
/* Horizontal Scaling */
/* Wii/NGC pixel clock = 13.5 Mhz */
/* "H32" pixel clock = Master Clock / 10 = 5.3693175 Mhz (NTSC) or 5.3203424 (PAL) */
/* "H40" pixel clock = Master Clock / 8 = 6,711646875 Mhz (NTSC) or 6,650428 Mhz (PAL) */
if (config.overscan & 2)
{
/* max visible range is ~712 pixels (= 348 'H40' pixels) */
*xscale = (reg[12] & 1) ? 356 : 363;
/* Horizontal borders are emulated */
if (reg[12] & 1)
{
/* 348 "H40" pixels = 348 * Wii pixel clock / "H40" pixel clock = approx. 700 (NTSC) or 707 (PAL) Wii/NGC pixels */
*xscale = (system_clock == MCLOCK_NTSC) ? 350 : 354;
}
else
{
/* 284 "H32" pixels = 284 * Wii pixel clock / "H40" pixel clock = approx. 714 (NTSC) or 721 (PAL) Wii/NGC pixels */
*xscale = (system_clock == MCLOCK_NTSC) ? 357 : 361;
}
}
else
{
/* overscan is simulated (black) */
*xscale = (system_hw == SYSTEM_GG) ? 204 : 327;
/* Horizontal borders are simulated */
if (system_hw == SYSTEM_GG)
{
/* 160 "H32" pixels = 160 * Wii pixel clock / "H32" pixel clock = approx. 403 Wii/NGC pixels (NTSC only) */
*xscale = 202;
}
else
{
/* 320 "H40" pixels = 256 "H32" pixels = 256 * Wii pixel clock / "H32" pixel clock = approx. 644 (NTSC) or 650 (PAL) Wii/NGC pixels */
*xscale = (system_clock == MCLOCK_NTSC) ? 322 : 325;
}
}
/* aspect correction for 16:9 screens */
/* Aspect correction for widescreen TV */
if (config.aspect & 2)
{
/* Keep 4:3 aspect ratio on 16:9 output */
*xscale = (*xscale * 3) / 4;
}
}
/* manual aspect ratio (default is full screen & not scaled if possible) */
/* Manual aspect ratio */
else
{
/* vertical borders */
if (config.overscan & 1)
/* By default, disable horizontal scaling */
*xscale = bitmap.viewport.w + (2 * bitmap.viewport.x);
/* Keep original aspect ratio in H32 modes */
if (!(reg[12] & 1))
{
*yscale = (gc_pal && !config.render) ? (vdp_pal ? (268*144 / bitmap.viewport.h):143) : (vdp_pal ? (224*144 / bitmap.viewport.h):120);
*xscale = (*xscale * 320) / 256;
}
else
/* Game Gear specific: if borders are disabled, upscale to fullscreen */
if (system_hw == SYSTEM_GG)
{
*yscale = (vheight == 192) ? 96 : 112;
if (gc_pal && !config.render)
if (!(config.overscan & 1))
{
*yscale = (*yscale * 134) / 112;
/* Active area height = approx. 224 non-interlaced lines (60hz) */
*yscale = 112;
}
if (!(config.overscan & 2))
{
/* Active area width = approx. 640 pixels */
*xscale = 320;
}
}
/* horizontal borders */
if (config.overscan & 2)
/* By default, keep NTSC aspect ratio */
if (gc_pal && !config.render)
{
*xscale = (reg[12] & 1) ? 348 : 355;
}
else
{
*xscale = 320;
/* Upscale PAL output */
*yscale = *yscale * VI_MAX_HEIGHT_PAL / VI_MAX_HEIGHT_NTSC;
}
/* add user scaling */
/* Add user scaling */
*xscale += config.xscale;
*yscale += config.yscale;
}
@ -1387,10 +1415,10 @@ void gx_video_Start(void)
gc_pal = 0;
}
/* VSYNC callbacks */
/* If TV mode matches emulated video mode, frame emulation is synchronized with Video Interrupt */
if (gc_pal == vdp_pal)
/* When VSYNC is forced ON or AUTO with TV mode matching emulated video mode, emulation is synchronized with video hardware */
if ((config.vsync == 1) && (gc_pal == vdp_pal))
{
/* VSYNC callback */
VIDEO_SetPreRetraceCallback(vi_callback);
VIDEO_Flush();
}
@ -1517,11 +1545,10 @@ void gx_video_Update(void)
if (config.ntsc)
{
vwidth = (reg[12] & 1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth);
}
/* texels size must be multiple of 4 */
vwidth = (vwidth >> 2) << 2;
vheight = (vheight >> 2) << 2;
/* texel width must remain multiple of 4 */
vwidth = (vwidth >> 2) << 2;
}
/* initialize texture object */
GXTexObj texobj;
@ -1619,7 +1646,7 @@ void gx_video_Update(void)
VIDEO_WaitVSync();
}
/* audio & video resynchronization */
/* Audio DMA need to be resynchronized with VSYNC */
audioStarted = 0;
}
}
@ -1647,29 +1674,21 @@ void gx_video_Init(void)
TV60hz_240p.viTVMode = VI_TVMODE_EURGB60_DS;
TV60hz_240i.viTVMode = VI_TVMODE_EURGB60_INT;
TV60hz_480i.viTVMode = VI_TVMODE_EURGB60_INT;
config.tv_mode = 1;
/* use harwdare vertical scaling to fill screen */
/* force harwdare vertical scaling to fill screen */
vmode = &TVPal574IntDfScale;
break;
case VI_NTSC: /* 480 lines (NTSC 60hz) */
TV60hz_240p.viTVMode = VI_TVMODE_NTSC_DS;
TV60hz_240i.viTVMode = VI_TVMODE_NTSC_INT;
TV60hz_480i.viTVMode = VI_TVMODE_NTSC_INT;
config.tv_mode = 0;
default: /* 480 lines (NTSC, MPAL or PAL 60Hz) */
#ifndef HW_RVL
/* force 480p on NTSC GameCube if the Component Cable is present */
if (VIDEO_HaveComponentCable()) vmode = &TVNtsc480Prog;
#endif
break;
default: /* 480 lines (PAL 60Hz) */
TV60hz_240p.viTVMode = VI_TVMODE(vmode->viTVMode >> 2, VI_NON_INTERLACE);
TV60hz_240i.viTVMode = VI_TVMODE(vmode->viTVMode >> 2, VI_INTERLACE);
TV60hz_480i.viTVMode = VI_TVMODE(vmode->viTVMode >> 2, VI_INTERLACE);
config.tv_mode = 2;
#ifndef HW_RVL
/* force 480p on GameCube if Component Cable is detected */
if (VIDEO_HaveComponentCable()) vmode = &TVNtsc480Prog;
#endif
break;
}

View File

@ -64,6 +64,13 @@ u32 Shutdown = 0;
u32 ConfigRequested = 1;
u32 frameticker;
#ifdef LOG_TIMING
u64 prevtime;
u32 frame_cnt;
u32 delta_time[LOGSIZE];
u32 delta_samp[LOGSIZE];
#endif
#ifdef HW_RVL
/****************************************************************************
@ -211,14 +218,7 @@ static void run_emulation(void)
if (!config.render && (gc_pal == vdp_pal))
{
/* framerate has changed, reinitialize audio timings */
if (vdp_pal)
{
audio_init(SAMPLERATE_48KHZ, interlaced ? 50.00 : (1000000.0/19968.0));
}
else
{
audio_init(SAMPLERATE_48KHZ, interlaced ? 59.94 : (1000000.0/16715.0));
}
audio_init(SAMPLERATE_48KHZ, get_framerate());
/* reinitialize sound chips */
sound_restore();
@ -250,18 +250,11 @@ static void run_emulation(void)
/* check interlaced mode change */
if (bitmap.viewport.changed & 4)
{
/* VSYNC "original" mode */
if (!config.render && (gc_pal == vdp_pal))
/* "original" mode */
if (!config.render)
{
/* framerate has changed, reinitialize audio timings */
if (vdp_pal)
{
audio_init(SAMPLERATE_48KHZ, interlaced ? 50.00 : (1000000.0/19968.0));
}
else
{
audio_init(SAMPLERATE_48KHZ, interlaced ? 59.94 : (1000000.0/16715.0));
}
audio_init(SAMPLERATE_48KHZ, get_framerate());
/* reinitialize sound chips */
sound_restore();
@ -280,6 +273,87 @@ static void run_emulation(void)
gx_audio_Stop();
gx_video_Stop();
#ifdef LOG_TIMING
if (cart.romsize)
{
FILE *f;
char filename[64];
memset(filename, 0, 64);
strcpy(filename,"timings-");
if (!config.vsync || (config.tv_mode == !vdp_pal))
{
strcat(filename,"no_");
}
else
{
if (gc_pal)
{
strcat(filename,"50hz_");
}
else
{
strcat(filename,"60hz_");
}
}
strcat(filename,"vsync-");
if (vdp_pal)
{
strcat(filename,"pal-");
}
else
{
strcat(filename,"ntsc-");
}
if (config.render == 2)
{
strcat(filename,"prog.txt");
}
else
{
if (!config.render && !interlaced)
{
strcat(filename,"no_");
}
strcat(filename,"int.txt");
}
f = fopen(filename,"a");
if (f != NULL)
{
int i;
u32 min,max;
double total = 0;
double nsamples = 0;
if (delta_time[LOGSIZE - 1] != 0)
{
frame_cnt = LOGSIZE;
}
min = max = delta_time[0];
for (i=0; i<frame_cnt; i++)
{
fprintf(f,"%d ns - %d samples (%5.8f samples/sec)\n", delta_time[i], delta_samp[i], 1000000000.0*(double)delta_samp[i]/(double)delta_time[i]/4.0);
total += delta_time[i];
nsamples += delta_samp[i] / 4.0;
if (min > delta_time[i]) min = delta_time[i];
if (max < delta_time[i]) max = delta_time[i];
}
fprintf(f,"\n");
fprintf(f,"min = %d ns\n", min);
fprintf(f,"max = %d ns\n", max);
fprintf(f,"avg = %8.5f ns (%5.8f samples/sec, %5.8f samples/frame)\n\n\n", total/(double)i, nsamples/total*1000000000.0, nsamples/(double)i);
fclose(f);
}
}
memset(delta_time,0,LOGSIZE);
memset(delta_samp,0,LOGSIZE);
frame_cnt = prevtime = 0;
#endif
/* show menu */
ConfigRequested = 0;
mainmenu();
@ -291,6 +365,35 @@ static void run_emulation(void)
}
}
/*********************************************************************************************************************************************************
Output exact framerate (used for sound chips emulation -- see sound.c)
*********************************************************************************************************************************************************/
double get_framerate(void)
{
/* VSYNC is forced OFF or AUTO with TV mode not matching emulated video mode: emulation is synchronized with audio hardware (DMA interrupt) */
if (!config.vsync || (config.tv_mode == !vdp_pal))
{
/* emulator will use original VDP framerate, which (theorically) provides more accurate frequencies but occasional video desynchronization */
return 0.0;
}
/* VSYNC is forced ON or AUTO with TV mode matching emulated video mode: emulation is synchronized with video hardware (VSYNC) */
/* emulator use exact output framerate for perfect video synchronization and (theorically) no sound skipping */
if (vdp_pal)
{
/* 288p -> 13500000 pixels/sec, 864 pixels/line, 312 lines/field -> fps = 13500000/864/312 = 50.08 hz */
/* 288i,576i -> 13500000 pixels/sec, 864 pixels/line, 312.5 lines/field (two fields = one frame = 625 lines) -> fps = 13500000/864/312.5 = 50.00 hz */
return (config.render || interlaced) ? (27000000.0/864.0/625.0) : (13500000.0/864.0/312.0);
}
else
{
/* 240p -> 13500000 pixels/sec, 858 pixels/line, 263 lines/field -> fps = 13500000/858/263 = 59.83 hz */
/* 240i,480i -> 13500000 pixels/sec, 858 pixels/line, 262.5 lines/field (two fields = one frame = 525 lines) -> fps = 13500000/858/262.5 = 59.94 hz */
/* 480p -> 27000000 pixels/sec, 858 pixels/line, 525 lines/field -> fps = 27000000/858/525 = 59.94 hz */
return (config.render || interlaced) ? (27000000.0/858.0/525.0) : (13500000.0/858.0/263.0);
}
}
/*******************************************
Restart emulation when loading a new game
********************************************/
@ -315,18 +418,8 @@ void reloadrom(void)
{
/* Initialize audio emulation */
/* To prevent any sound skipping, sound chips must run at the exact same speed as the rest of emulation (see sound.c) */
/* When TV output mode matches emulated video mode, we use video hardware interrupt (VSYNC) and exact framerates for perfect synchronization */
/* In 60Hz TV modes, Wii & GC framerates have been measured to be 59.94 (interlaced or progressive) and ~59.825 fps (non-interlaced) */
/* In 50Hz TV modes, Wii & GC framerates have been measured to be 50.00 (interlaced) and ~50.845 fps (non-interlaced) */
/* When modes does not match, emulation is synchronized with audio hardware interrupt (DMA) and we use default framerates (50Hz for PAL, 60Hz for NTSC). */
if (vdp_pal)
{
audio_init(SAMPLERATE_48KHZ, (config.tv_mode == 0) ? 50.0 : (config.render ? 50.00 : (1000000.0/19968.0)));
}
else
{
audio_init(SAMPLERATE_48KHZ, (config.tv_mode == 1) ? 60.0 : (config.render ? 59.94 : (1000000.0/16715.0)));
}
interlaced = 0;
audio_init(SAMPLERATE_48KHZ, get_framerate());
/* Switch virtual system on */
system_init();
@ -407,7 +500,7 @@ int main (int argc, char *argv[])
/* initialize video engine */
gx_video_Init();
#ifdef HW_DOL
#ifndef HW_RVL
/* initialize DVD interface */
DVD_Init();
#endif

View File

@ -44,10 +44,20 @@
/* globals */
extern void legal(void);
extern double get_framerate(void);
extern void reloadrom(void);
extern void shutdown(void);
extern u32 frameticker;
extern u32 Shutdown;
extern u32 ConfigRequested;
#ifdef LOG_TIMING
#include <ogc/lwp_watchdog.h>
#define LOGSIZE 2000
extern u64 prevtime;
extern u32 frame_cnt;
extern u32 delta_time[LOGSIZE];
extern u32 delta_samp[LOGSIZE];
#endif
#endif /* _OSD_H_ */

View File

@ -51,7 +51,7 @@ void activator_reset(int index)
activator[index].Counter = 0;
}
static __inline__ unsigned char activator_read(int port)
INLINE unsigned char activator_read(int port)
{
/* IR sensors 1-16 data (active low) */
uint16 data = ~input.pad[port << 2];
@ -85,7 +85,7 @@ static __inline__ unsigned char activator_read(int port)
return temp;
}
static __inline__ void activator_write(int index, unsigned char data, unsigned char mask)
INLINE void activator_write(int index, unsigned char data, unsigned char mask)
{
/* update bits set as output only */
data = (activator[index].State & ~mask) | (data & mask);

View File

@ -71,7 +71,7 @@ void gamepad_refresh(int port)
}
}
static __inline__ unsigned char gamepad_read(int port)
INLINE unsigned char gamepad_read(int port)
{
/* bit 7 is latched, returns current TH state */
unsigned int data = (gamepad[port].State & 0x40) | 0x3F;
@ -142,7 +142,7 @@ static __inline__ unsigned char gamepad_read(int port)
return data;
}
static __inline__ void gamepad_write(int port, unsigned char data, unsigned char mask)
INLINE void gamepad_write(int port, unsigned char data, unsigned char mask)
{
/* update bits set as output only */
data = (gamepad[port].State & ~mask) | (data & mask);

View File

@ -140,7 +140,7 @@ void lightgun_refresh(int port)
/* Sega Phaser */
/*--------------------------------------------------------------------------*/
static __inline__ unsigned char phaser_read(int port)
INLINE unsigned char phaser_read(int port)
{
/* TL returns TRIGGER (INPUT_A) button status (active low) */
unsigned char temp = ~((input.pad[port] >> 2) & 0x10);

View File

@ -49,7 +49,7 @@ void paddle_reset(int index)
paddle[index].State = 0x40;
}
static __inline__ unsigned char paddle_read(int port)
INLINE unsigned char paddle_read(int port)
{
/* FIRE button status (active low) */
unsigned char temp = ~(input.pad[port] & 0x10);
@ -83,7 +83,7 @@ static __inline__ unsigned char paddle_read(int port)
return temp;
}
static __inline__ void paddle_write(int index, unsigned char data, unsigned char mask)
INLINE void paddle_write(int index, unsigned char data, unsigned char mask)
{
/* update bits set as output only */
paddle[index].State = (paddle[index].State & ~mask) | (data & mask);

View File

@ -52,7 +52,7 @@ void sportspad_reset(int index)
sportspad[index].Counter = 0;
}
static __inline__ unsigned char sportspad_read(int port)
INLINE unsigned char sportspad_read(int port)
{
/* Buttons 1(B) & 2(C) status (active low) */
unsigned char temp = ~(input.pad[port] & 0x30);
@ -98,7 +98,7 @@ static __inline__ unsigned char sportspad_read(int port)
return temp;
}
static __inline__ void sportspad_write(int index, unsigned char data, unsigned char mask)
INLINE void sportspad_write(int index, unsigned char data, unsigned char mask)
{
/* update bits set as output only */
data = (sportspad[index].State & ~mask) | (data & mask);

View File

@ -80,7 +80,7 @@ void teamplayer_reset(int port)
teamplayer[port].Counter = 0;
}
static __inline__ unsigned int teamplayer_read(int port)
INLINE unsigned int teamplayer_read(int port)
{
unsigned int counter = teamplayer[port].Counter;
@ -131,7 +131,7 @@ static __inline__ unsigned int teamplayer_read(int port)
}
}
static __inline__ void teamplayer_write(int port, unsigned char data, unsigned char mask)
INLINE void teamplayer_write(int port, unsigned char data, unsigned char mask)
{
/* update bits set as output only */
unsigned int state = (teamplayer[port].State & ~mask) | (data & mask);

View File

@ -593,14 +593,25 @@ void region_autodetect(void)
}
}
/* forced console region */
/* force console region if requested */
if (config.region_detect == 1) region_code = REGION_USA;
else if (config.region_detect == 2) region_code = REGION_EUROPE;
else if (config.region_detect == 3) region_code = REGION_JAPAN_NTSC;
else if (config.region_detect == 4) region_code = REGION_JAPAN_PAL;
/* PAL/NTSC timings */
/* autodetect PAL/NTSC timings */
vdp_pal = (region_code >> 6) & 0x01;
/* autodetect PAL/NTSC master clock */
system_clock = vdp_pal ? MCLOCK_PAL : MCLOCK_NTSC;
/* force PAL/NTSC timings if requested */
if (config.vdp_mode == 1) vdp_pal = 0;
else if (config.vdp_mode == 2) vdp_pal = 1;
/* force PAL/NTSC master clock if requested */
if (config.master_clock == 1) system_clock = MCLOCK_NTSC;
else if (config.master_clock == 2) system_clock = MCLOCK_PAL;
}

View File

@ -40,7 +40,7 @@
/* Import the configuration for this build */
#include "m68kconf.h"
#include "macros.h"
/* ======================================================================== */
/* ============================ GENERAL DEFINES =========================== */
@ -122,8 +122,6 @@ typedef enum
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
/* ======================================================================== */
#include "macros.h"
/* 68k memory map structure */
typedef struct
{

View File

@ -121,16 +121,6 @@
#define M68K_USE_64_BIT OPT_OFF
/* Set to your compiler's static inline keyword to enable it, or
* set it to blank to disable it.
* If you define INLINE in the makefile, it will override this value.
* NOTE: not enabling inline functions will SEVERELY slow down emulation.
*/
#ifndef INLINE
#define INLINE static __inline__
#endif /* INLINE */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */

View File

@ -32,5 +32,18 @@
#define WRITE_WORD_LONG(BASE, ADDR, VAL) *(uint32 *)((BASE) + (ADDR)) = VAL & 0xffffffff
#endif
/* C89 compatibility */
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327f
#endif /* M_PI */
/* Set to your compiler's static inline keyword to enable it, or
* set it to blank to disable it.
* If you define INLINE in the makefile, it will override this value.
* NOTE: not enabling inline functions will SEVERELY slow down emulation.
*/
#ifndef INLINE
#define INLINE static __inline__
#endif /* INLINE */
#endif /* _MACROS_H_ */

View File

@ -47,14 +47,14 @@
/* machine lock up. */
/*--------------------------------------------------------------------------*/
static __inline__ void z80_unused_w(unsigned int address, unsigned char data)
INLINE void z80_unused_w(unsigned int address, unsigned char data)
{
#ifdef LOGERROR
error("Z80 unused write %04X = %02X (%x)\n", address, data, Z80.pc.w.l);
#endif
}
static __inline__ unsigned char z80_unused_r(unsigned int address)
INLINE unsigned char z80_unused_r(unsigned int address)
{
#ifdef LOGERROR
error("Z80 unused read %04X (%x)\n", address, Z80.pc.w.l);
@ -62,7 +62,7 @@ static __inline__ unsigned char z80_unused_r(unsigned int address)
return 0xFF;
}
static __inline__ void z80_lockup_w(unsigned int address, unsigned char data)
INLINE void z80_lockup_w(unsigned int address, unsigned char data)
{
#ifdef LOGERROR
error("Z80 lockup write %04X = %02X (%x)\n", address, data, Z80.pc.w.l);
@ -74,7 +74,7 @@ static __inline__ void z80_lockup_w(unsigned int address, unsigned char data)
}
}
static __inline__ unsigned char z80_lockup_r(unsigned int address)
INLINE unsigned char z80_lockup_r(unsigned int address)
{
#ifdef LOGERROR
error("Z80 lockup read %04X (%x)\n", address, Z80.pc.w.l);

View File

@ -2,6 +2,8 @@
#define _SHARED_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "types.h"

View File

@ -15,14 +15,14 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
/* C Conversion by Eke-Eke for use in Genesis Plus GX (2009). */
#include "Fir_Resampler.h"
#include "shared.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "Fir_Resampler.h"
#include "macros.h"
/* sound buffer */
static sample_t *buffer = NULL;
static int buffer_size = 0;

View File

@ -34,7 +34,7 @@
#include <string.h>
#include <math.h>
#include "eq.h"
#include "types.h"
#include "macros.h"
/* -----------

View File

@ -52,7 +52,7 @@ static void (*YM_Update)(int *buffer, int length);
static void (*YM_Write)(unsigned int a, unsigned int v);
/* Run FM chip for required M-cycles */
static __inline__ void fm_update(unsigned int cycles)
INLINE void fm_update(unsigned int cycles)
{
if (cycles > fm_cycles_count)
{
@ -82,7 +82,7 @@ static __inline__ void fm_update(unsigned int cycles)
}
/* Run PSG chip for required M-cycles */
static __inline__ void psg_update(unsigned int cycles)
INLINE void psg_update(unsigned int cycles)
{
if (cycles > psg_cycles_count)
{
@ -103,25 +103,29 @@ void sound_init(void)
{
/* Number of M-cycles executed per second. */
/* */
/* The original Genesis would run exactly 53693175 M-cycles (53203424 for PAL), with */
/* All emulated chips are kept in sync by using a common oscillator (MCLOCK) */
/* */
/* The original console would run exactly 53693175 M-cycles (53203424 for PAL), with */
/* 3420 M-cycles per line and 262 (313 for PAL) lines per frame, which gives an exact */
/* framerate of 59.92 (49.70 for PAL) fps. */
/* */
/* On some systems, the output framerate is not exactly 60 or 50 fps because we need */
/* 100% smooth video and therefore frame emulation is synchronized with VSYNC, which */
/* period is never exactly 1/60 or 1/50 seconds. */
/* Since audio samples are generated at the end of the frame, to prevent audio skipping */
/* or lag between emulated frames, number of samples rendered per frame must be set to */
/* output samplerate (number of samples played per second) divided by output framerate */
/* (number of frames emulated per seconds). */
/* */
/* For optimal sound rendering, input samplerate (number of samples rendered per frame) */
/* is the exact output samplerate (number of samples played per second) divided by the */
/* exact output framerate (number of frames emulated per seconds). */
/* On some systems, we may want to achieve 100% smooth video rendering by synchronizing */
/* frame emulation with VSYNC, which frequency is generally not exactly those values. */
/* In that case, number of frames emulated per seconds is the same as the number of */
/* frames rendered per seconds by the host system video hardware. */
/* */
/* This ensure there is no audio skipping or lag between emulated frames, while keeping */
/* accurate timings for sound chips execution & synchronization. */
/* When no framerate is specified, base clock is original master clock value. */
/* Otherwise, it is based on the output framerate. */
/* */
double mclk = MCYCLES_PER_LINE * lines_per_frame * snd.frame_rate;
double mclk = snd.frame_rate ? (MCYCLES_PER_LINE * lines_per_frame * snd.frame_rate) : system_clock;
/* For better accuracy, sound chips run in synchronization with 68k and Z80 cpus */
/* These values give the exact number of M-cycles between 2 rendered samples. */
/* These values give the exact number of M-cycles executed per rendered samples. */
/* we use 21.11 fixed point precision (max. mcycle value is 3420*313 i.e 21 bits max) */
psg_cycles_ratio = (unsigned int)(mclk / (double) snd.sample_rate * 2048.0);
fm_cycles_ratio = psg_cycles_ratio;
@ -129,7 +133,7 @@ void sound_init(void)
psg_cycles_count = 0;
/* Initialize core emulation (input clock based on input frequency for 100% accuracy) */
/* By default, both chips are running at the output frequency. */
/* By default, both PSG & FM chips are running at the output frequency. */
SN76489_Init(mclk/15.0,snd.sample_rate);
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
@ -166,8 +170,9 @@ void sound_init(void)
}
#ifdef LOGSOUND
error("%d mcycles per PSG samples\n", psg_cycles_ratio);
error("%d mcycles per FM samples\n", fm_cycles_ratio);
error("%f mcycles per second\n", mclk);
error("%d mcycles per PSG sample\n", psg_cycles_ratio);
error("%d mcycles per FM sample\n", fm_cycles_ratio);
#endif
}

View File

@ -27,13 +27,8 @@ to do:
/** EkeEke (2011): removed multiple chips support, cleaned code & added FM board interface for Genesis Plus GX **/
#include <math.h>
#include "shared.h"
/* compiler dependence */
#define INLINE static __inline__
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (EG timing) */
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */

View File

@ -125,19 +125,8 @@
/* YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include "shared.h"
/* compiler dependence */
#ifndef INLINE
#define INLINE static __inline__
#endif
/* globals */
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */

View File

@ -49,8 +49,9 @@ t_snd snd;
uint32 mcycles_vdp;
uint32 mcycles_z80;
uint32 mcycles_68k;
int16 SVP_cycles = 800;
uint8 system_hw;
uint32 system_clock;
int16 SVP_cycles = 800;
static uint8 pause_b;
static EQSTATE eq;
@ -60,7 +61,7 @@ static int32 llp,rrp;
* Audio subsystem
****************************************************************/
int audio_init(int samplerate, float framerate)
int audio_init(int samplerate, double framerate)
{
/* Shutdown first */
audio_shutdown();
@ -72,8 +73,25 @@ int audio_init(int samplerate, float framerate)
snd.sample_rate = samplerate;
snd.frame_rate = framerate;
/* Calculate the sound buffer size (for one frame) */
snd.buffer_size = (int)(samplerate / framerate) + 32;
/* If no framerate is specified, assume emulator is running at the original frequency */
if (!framerate)
{
if (vdp_pal)
{
/* PAL mode -> MCLK cycles/sec, 3420 cycles/line, 313 lines/field */
/* fps = MCLK/3420/313 = 49.70 hz (PAL console) or 50.16 hz (NTSC console w/ 50 hz switch) */
framerate = (double)system_clock / (double)MCYCLES_PER_LINE / 313.0;
}
else
{
/* NTSC mode -> MCLK cycles/sec, 3420 cycles/line, 262 lines/field */
/* fps = MCLK/3420/262 = 59.92 hz (NTSC console) or 59.38 hz (PAL console w/ 60 hz switch) */
framerate = (double)system_clock / (double)MCYCLES_PER_LINE / 262.0;
}
}
/* Sound buffer maximal size (for at least one frame) */
snd.buffer_size = (int)((double)samplerate / framerate) + 32;
/* SN76489 stream buffer */
snd.psg.buffer = (int16 *) malloc(snd.buffer_size * sizeof(int16));

View File

@ -53,6 +53,10 @@
#define SYSTEM_PBC 0x81
#define SYSTEM_PICO 0x82
/* NTSC & PAL Master Clock frequencies */
#define MCLOCK_NTSC 53693175
#define MCLOCK_PAL 53203424
/* Number of M-Cycles executed per line */
#define MCYCLES_PER_LINE 3420
@ -81,7 +85,7 @@ typedef struct
typedef struct
{
int sample_rate; /* Output Sample rate (8000-48000) */
float frame_rate; /* Output Frame rate (usually 50 or 60 frames per second) */
double frame_rate; /* Output Frame rate (usually 50 or 60 frames per second) */
int enabled; /* 1= sound emulation is enabled */
int buffer_size; /* Size of sound buffer (in bytes) */
int16 *buffer[2]; /* Signed 16-bit stereo sound data */
@ -106,9 +110,10 @@ extern uint32 mcycles_68k;
extern uint32 mcycles_vdp;
extern int16 SVP_cycles;
extern uint8 system_hw;
extern uint32 system_clock;
/* Function prototypes */
extern int audio_init(int samplerate,float framerate);
extern int audio_init(int samplerate, double framerate);
extern void audio_reset(void);
extern void audio_shutdown(void);
extern int audio_update(void);

View File

@ -11,8 +11,3 @@
#define int8 signed char
#define int16 signed short
#define int32 signed int
/* C89 compatibility */
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif

View File

@ -57,7 +57,7 @@ extern sms_ntsc_t *sms_ntsc;
#undef READ_LONG
#undef WRITE_LONG
static __inline__ uint32 READ_LONG(void *address)
INLINE uint32 READ_LONG(void *address)
{
if ((uint32)address & 3)
{
@ -76,7 +76,7 @@ static __inline__ uint32 READ_LONG(void *address)
else return *(uint32 *)address;
}
static __inline__ void WRITE_LONG(void *address, uint32 data)
INLINE void WRITE_LONG(void *address, uint32 data)
{
if ((uint32)address & 3)
{
@ -948,7 +948,7 @@ static uint32 make_lut_bgobj_m4(uint32 bx, uint32 sx)
/* Pixel layer merging function */
/*--------------------------------------------------------------------------*/
static __inline__ void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, int width)
INLINE void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, int width)
{
do
{

View File

@ -27,6 +27,8 @@ void set_config_defaults(void)
/* system options */
config.system = 0; /* = AUTO (or SYSTEM_SG, SYSTEM_MARKIII, SYSTEM_SMS, SYSTEM_SMS2, SYSTEM_GG, SYSTEM_MD) */
config.region_detect = 0; /* = AUTO (1 = USA, 2 = EUROPE, 3 = JAPAN/NTSC, 4 = JAPAN/PAL) */
config.vdp_mode = 0; /* = AUTO (1 = NTSC, 2 = PAL) */
config.master_clock = 0; /* = AUTO (1 = NTSC, 2 = PAL) */
config.force_dtack = 0;
config.addr_error = 1;
config.bios = 0;

View File

@ -29,6 +29,8 @@ typedef struct
float rolloff;
uint8 system;
uint8 region_detect;
uint8 vdp_mode;
uint8 master_clock;
uint8 force_dtack;
uint8 addr_error;
uint8 tmss;

View File

@ -729,7 +729,7 @@ int main (int argc, char **argv)
bitmap.viewport.changed = 3;
/* initialize emulation */
audio_init(SOUND_FREQUENCY, vdp_pal ? 50.0 : 60.0);
audio_init(SOUND_FREQUENCY, 0);
system_init();
/* load SRAM */

View File

@ -7,42 +7,23 @@
* UINT8 - Unsigned 8-bit Integer INT8 - Signed 8-bit integer *
* UINT16 - Unsigned 16-bit Integer INT16 - Signed 16-bit integer *
* UINT32 - Unsigned 32-bit Integer INT32 - Signed 32-bit integer *
* UINT64 - Unsigned 64-bit Integer INT64 - Signed 64-bit integer *
* *
* *
* The macro names for the artithmatic operations are composed as follows: *
* *
* XXX_R_A_B, where XXX - 3 letter operation code (ADD, SUB, etc.) *
* R - The type of the result *
* A - The type of operand 1 *
* B - The type of operand 2 (if binary operation) *
* *
* Each type is one of: U8,8,U16,16,U32,32,U64,64 *
* *
*******************************************************************************/
#ifndef OSD_CPU_H
#define OSD_CPU_H
#ifndef NGC
#ifndef DOS
#include "basetsd.h"
#endif
#undef TRUE
#undef FALSE
#define TRUE 1
#define TRUE 1
#define FALSE 0
#endif
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned int UINT32;
__extension__ typedef unsigned long long UINT64;
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
__extension__ typedef signed long long INT64;
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned int UINT32;
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
/******************************************************************************
* Union of UINT8, UINT16 and UINT32 in native endianess of the target