[Core/VDP]

* improved sprites processing accuracy.
* fixed VBLANK transition line checks.
* code cleanup and (minor) optimizations.

[Core/Sound]
* increased FM internal sample size to 32-bit to avoid overflow when adding channels.
* added preliminary emulation of YM2612 DAC precision (can be configured to match real console output).
* added configurable roll-off for FIR filtering in High-Quality FM mode.

[Wii]
*added support to enable/disable Video Encoder Trap Filter: can help reproducing "color blending" as on a real Genesis (composite video only).
*added support to configure Video Encoder gamma correction.
This commit is contained in:
ekeeke31 2010-02-28 19:55:43 +00:00
parent 62b3cce887
commit ed11eb0133
19 changed files with 1314 additions and 457 deletions

View File

@ -10,23 +10,25 @@ 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 upon reset.
* removed outdated Gens YM2612 core
* added faster FIR resampler (thanks to Blargg & AamirM), dropped libsamplerate support.
* fixed YM2612 state on reset.
* removed outdated & less accurate Gens YM2612 core
* added preliminar emulation of YM2612 DAC original resolution (configurable).
* added configurable & faster FIR resampler (thanks to Blargg & AamirM), dropped libsamplerate support.
* added configurable Low-Pass filtering
* added 3-Band Equalizer to support fully configurable sound filtering (thanks to Neil C).
* added an option to boost SN76489 Noise Channel.
* added configurable 3-Band Equalizer (thanks to Neil C).
* added support for SN76489 Noise Channel boost (optional).
* modified SN76489 cut-off frequency.
[Core/VDP]
---------------
* added support for CRAM writes during horizontal blanking.
* added support for 2-Cell vertical scrolling in Interlaced 2 mode (unused by games ?)
* fixed 2-Cell vertical scrolling when column 0 is shifted.
* added support for CRAM writes during horizontal blanking (Striker, Zero the Kamikaze Squirrel,...)
* added support for 2-Cell vertical scrolling in Interlaced 2 mode
* fixed VBLANK transition line checks
* improved sprite masking accuracy (thanks to Nemesis for his sprite test program)
* improved HBLANK flag timing accuracy: fixes Mega Turrican (Sky level)
* improved sprites processing timing accuracy: fixes (un)masked sprites in Mickey Mania (3D level), Sonic 2 (VS mode).
* improved sprites processing accuracy: fixes (un)masked sprites in Mickey Mania (3D level), Sonic 2 (VS mode).
* improved horizontal blanking & HINT/VINT occurence timing accuracy, as measured on real hardware.
* improved H-Counter accuracy in 40-cell mode, as measured on real hardware.
* improved color accuracy in VDP highlight mode to match results observed on real hardware.
@ -54,14 +56,14 @@ of samples per frame and keeping PSG & FM chips in sync.
[Gamecube/Wii]
---------------
* new! FONT engine (using internal IPL font & GX hardware rendering).
* new! GUI engine (with PCM/OGG sound support, using GX hardware rendering & multithreading).
* new! interface design (incl. IR pointing, game snapshots, visual & sound effects, BGM...).
* implemented new FONT engine (using internal IPL font & GX hardware rendering).
* implemented custom GUI engine (with PCM/OGG sound support, multithreading & using GX hardware for rendering)
* new interface design (incl. IR pointing, game snapshots, visual & sound effects, BGM...).
* improved audio/video back-end synchronization to ensure 100% smooth video & audio playback.
* improved reset button behavior, now works more like the real Genesis reset button.
* improved lightgun cursors layout.
* fixed stability issues and memory leaks.
* compiled with Devkitpro/PPC r18 and last libogc/libfat (support for SDHC, new DVDX, etc)
* compiled with devkitPPC r19 & libOGC 1.8.1 (SDHC support, new DVDX, etc)

View File

@ -87,7 +87,8 @@ static inline void lightgun_update(int num)
if (io_reg[5] & 0x80)
{
/* External Interrupt ? */
if (reg[11] & 0x08) irq_status = (irq_status & ~0x40) | 0x12;
if (reg[11] & 0x08)
irq_status = (irq_status & ~0x40) | 0x12;
/* Horizontal Counter Latch:
1) some games does not set HVC latch but instead use bigger X offset

View File

@ -48,7 +48,8 @@ void config_load(void)
char version[16];
fread(version, 16, 1, fp);
fclose(fp);
if (strcmp(version,VERSION)) return;
if (strcmp(version,VERSION))
return;
/* read file */
fp = fopen(fname, "rb");
@ -77,6 +78,8 @@ void config_default(void)
config.lg = 1.0;
config.mg = 1.0;
config.hg = 1.0;
config.rolloff = 0.995;
config.dac_bits = 14;
/* system options */
config.region_detect = 0;
@ -100,6 +103,10 @@ void config_default(void)
config.render = 0;
config.ntsc = 0;
config.bilinear = 1;
#ifdef HW_RVL
config.trap = 1;
config.gamma = VI_GM_1_0 / 10.0;
#endif
/* controllers options */
config.gun_cursor[0] = 1;

View File

@ -42,6 +42,8 @@ typedef struct
float lg;
float mg;
float hg;
float rolloff;
uint8 dac_bits;
uint8 region_detect;
uint8 force_dtack;
uint8 addr_error;
@ -59,6 +61,10 @@ typedef struct
uint8 render;
uint8 ntsc;
uint8 bilinear;
#ifdef HW_RVL
uint8 trap;
float gamma;
#endif
uint8 gun_cursor[2];
uint8 invert_mouse;
uint16 pad_keymap[4][MAX_KEYS];

View File

@ -1278,8 +1278,8 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio
else
{
/* float type */
if (*(float *)option < 0.0) sprintf(msg,"-%1.2f",fabs(*(float *)option));
else sprintf(msg,"%1.2f",fabs(*(float *)option));
if (*(float *)option < 0.0) sprintf(msg,"-%1.3f",fabs(*(float *)option));
else sprintf(msg,"%1.3f",fabs(*(float *)option));
}
/* draw option text */

View File

@ -216,22 +216,24 @@ static gui_item items_options[5] =
{NULL,Option_menu_png ,"","Menu settings", 370,286,60,92}
};
/* Audio options menu */
static gui_item items_audio[10] =
/* Audio options */
static gui_item items_audio[12] =
{
{NULL,NULL,"High-Quality FM: LINEAR", "Setup YM2612 resampling", 52,132,276,48},
{NULL,NULL,"PSG Noise Boost: OFF", "Boost PSG Noise Channel", 52,132,276,48},
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 output level", 52,132,276,48},
{NULL,NULL,"High-Quality FM: ON", "Enable/disable YM2612 resampling", 52,132,276,48},
{NULL,NULL,"FM Roll-off: 0.999", "Adjust FIR low-pass filtering", 52,132,276,48},
{NULL,NULL,"FM Resolution: MAX", "Adjust YM2612 DAC precision", 52,132,276,48},
{NULL,NULL,"FM Volume: 1.00", "Adjust YM2612 output level", 52,132,276,48},
{NULL,NULL,"PSG Volume: 2.50", "Adjust SN76489 output level", 52,132,276,48},
{NULL,NULL,"PSG Noise Boost: OFF", "Boost SN76489 Noise Channel", 52,132,276,48},
{NULL,NULL,"Filtering: 3-BAND EQ", "Setup Audio filtering", 52,132,276,48},
{NULL,NULL,"Low Gain: 1.00", "Adjust EQ Low Band Gain", 52,132,276,48},
{NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Middle Band Gain", 52,132,276,48},
{NULL,NULL,"Mid Gain: 1.00", "Adjust EQ Mid Band Gain", 52,132,276,48},
{NULL,NULL,"High Gain: 1.00", "Adjust EQ High BandGain", 52,132,276,48},
{NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Low Band Frequency", 52,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ High Band Frequency",52,132,276,48}
{NULL,NULL,"Low Freq: 200 Hz", "Adjust EQ Lowest Frequency", 52,132,276,48},
{NULL,NULL,"High Freq: 20000 Hz", "Adjust EQ Highest Frequency", 52,132,276,48}
};
/* System options menu */
/* System options */
static gui_item items_system[7] =
{
{NULL,NULL,"Console Region: AUTO", "Select system region", 52,132,276,48},
@ -243,20 +245,28 @@ static gui_item items_system[7] =
{NULL,NULL,"SVP Cycles: 1500", "Adjust SVP chip emulation speed", 52,132,276,48}
};
/* Video options menu */
/* Video options */
#ifdef HW_RVL
static gui_item items_video[10] =
#else
static gui_item items_video[8] =
#endif
{
{NULL,NULL,"Display: PROGRESSIVE", "Select video mode type", 52,132,276,48},
{NULL,NULL,"TV mode: 50/60Hz", "Select video refresh rate", 52,132,276,48},
{NULL,NULL,"Bilinear Filter: OFF", "Enable/disable hardware filtering", 52,132,276,48},
{NULL,NULL,"Display: PROGRESSIVE", "Select video signal type", 52,132,276,48},
{NULL,NULL,"TV mode: 50/60Hz", "Select video signal frequency", 52,132,276,48},
{NULL,NULL,"GX Bilinear Filter: OFF", "Enable/disable texture hardware filtering", 52,132,276,48},
#ifdef HW_RVL
{NULL,NULL,"VI Trap Filter: ON", "Enable/disable video hardware filtering", 52,132,276,48},
{NULL,NULL,"VI Gamma Correction: 1.0","Adjust video hardware gamma correction", 52,132,276,48},
#endif
{NULL,NULL,"NTSC Filter: COMPOSITE", "Enable/disable NTSC software filtering", 52,132,276,48},
{NULL,NULL,"Borders: OFF", "Enable/disable original overscan emulation",52,132,276,48},
{NULL,NULL,"Borders: OFF", "Enable/disable overscan emulation", 52,132,276,48},
{NULL,NULL,"Aspect: ORIGINAL (4:3)", "Select display aspect ratio", 52,132,276,48},
{NULL,NULL,"Screen Position (+0,+0)", "Adjust display position", 52,132,276,48},
{NULL,NULL,"Screen Size (+0,+0)", "Adjust display size", 52,132,276,48}
{NULL,NULL,"Screen Scaling (+0,+0)", "Adjust display scaling", 52,132,276,48}
};
/* Preferences menu */
/* Menu options */
static gui_item items_prefs[7] =
{
{NULL,NULL,"Auto SRAM: OFF", "Enable/disable automatic SRAM", 52,132,276,48},
@ -265,7 +275,7 @@ static gui_item items_prefs[7] =
{NULL,NULL,"BGM Volume: 100", "Adjust background music volume", 52,132,276,48},
{NULL,NULL,"BG Color: DEFAULT", "Change background color", 52,132,276,48},
{NULL,NULL,"Screen Width: 658", "Adjust Screen Width", 52,132,276,48},
{NULL,NULL,"Confirmation Box: OFF", "Enable/disable user confirmation", 52,132,276,48}
{NULL,NULL,"Confirm Box: OFF", "Enable/disable user confirmation", 52,132,276,48}
};
/*****************************************************************************/
@ -436,7 +446,7 @@ static gui_menu menu_audio =
{
"Audio Settings",
0,0,
10,4,6,0,
8,4,6,0,
items_audio,
buttons_list,
bg_list,
@ -688,61 +698,146 @@ static void prefmenu ()
* Audio Settings menu
*
****************************************************************************/
static void soundmenu ()
static int update_snd_items(void)
{
int ret, quit = 0;
gui_menu *m = &menu_audio;
gui_item *items = m->items;
float psg_volume = (float)config.psg_preamp/100.0;
int offset;
float fm_volume = (float)config.fm_preamp/100.0;
float psg_volume = (float)config.psg_preamp/100.0;
if (config.hq_fm)
{
sprintf (items[0].text, "High-Quality FM: ON");
sprintf (items[1].text, "FM Roll-off: %1.3f",config.rolloff);
strcpy (items[1].comment, "Adjust FIR low-pass filtering");
offset = 2;
}
else
{
sprintf (items[0].text, "High-Quality FM: OFF");
offset = 1;
}
strcpy(items[offset].comment, "Adjust YM2612 DAC precision");
strcpy(items[offset+1].comment, "Adjust YM2612 output level");
strcpy(items[offset+2].comment, "Adjust SN76489 output level");
strcpy(items[offset+3].comment, "Boost SN76489 Noise Channel");
strcpy(items[offset+4].comment, "Configure Audio filtering");
if (config.dac_bits < 14)
sprintf (items[offset].text, "FM Resolution: %d bits", config.dac_bits);
else
sprintf (items[offset].text, "FM Resolution: MAX");
sprintf (items[offset+1].text, "FM Volume: %1.2f", fm_volume);
sprintf (items[offset+2].text, "PSG Volume: %1.2f", psg_volume);
sprintf (items[offset+3].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
sprintf (items[1].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
sprintf (items[2].text, "PSG Volume: %1.2f", psg_volume);
sprintf (items[3].text, "FM Volume: %1.2f", (double)config.fm_preamp/100.0);
if (config.filter == 2) sprintf (items[4].text, "Filtering: 3-BAND EQ");
else if (config.filter == 1) sprintf (items[4].text, "Filtering: LOW PASS");
else sprintf (items[4].text, "Filtering: OFF");
if (config.filter == 2)
{
sprintf (items[5].text, "Low Gain: %1.2f", config.lg);
strcpy (items[5].comment, "Adjust EQ Low Band Gain");
sprintf (items[6].text, "Middle Gain: %1.2f", config.mg);
sprintf (items[7].text, "High Gain: %1.2f", config.hg);
sprintf (items[8].text, "Low Freq: %d", config.low_freq);
sprintf (items[9].text, "High Freq: %d", config.high_freq);
sprintf (items[offset+4].text, "Filtering: 3-BAND EQ");
sprintf (items[offset+5].text, "Low Gain: %1.2f", config.lg);
sprintf (items[offset+6].text, "Middle Gain: %1.2f", config.mg);
sprintf (items[offset+7].text, "High Gain: %1.2f", config.hg);
sprintf (items[offset+8].text, "Low Freq: %d", config.low_freq);
sprintf (items[offset+9].text, "High Freq: %d", config.high_freq);
strcpy (items[offset+5].comment, "Adjust EQ Low Band Gain");
strcpy (items[offset+6].comment, "Adjust EQ Mid Band Gain");
strcpy (items[offset+7].comment, "Adjust EQ High Band Gain");
strcpy (items[offset+8].comment, "Adjust EQ Lowest Frequency");
strcpy (items[offset+9].comment, "Adjust EQ Highest Frequency");
m->max_items = offset + 10;
}
else if (config.filter == 1)
{
sprintf (items[5].text, "Low-Pass Rate: %d %%", config.lp_range);
strcpy (items[5].comment, "Adjust Low Pass filter");
sprintf (items[offset+4].text, "Filtering: LOW-PASS");
sprintf (items[offset+5].text, "Low-Pass Rate: %d %%", config.lp_range);
strcpy (items[offset+5].comment, "Adjust Low Pass filter");
m->max_items = offset + 6;
}
else
{
sprintf (items[offset+4].text, "Filtering: OFF");
m->max_items = offset + 5;
}
sprintf (items[offset+6].text, "Middle Gain: %1.2f", config.mg);
sprintf (items[offset+7].text, "High Gain: %1.2f", config.hg);
sprintf (items[offset+8].text, "Low Freq: %d", config.low_freq);
sprintf (items[offset+9].text, "High Freq: %d", config.high_freq);
strcpy (items[offset+5].comment, "Adjust EQ Low Band Gain");
strcpy (items[offset+6].comment, "Adjust EQ Mid Band Gain");
strcpy (items[offset+7].comment, "Adjust EQ High Band Gain");
strcpy (items[offset+8].comment, "Adjust EQ Lowest Frequency");
strcpy (items[offset+9].comment, "Adjust EQ Highest Frequency");
return offset;
}
static void soundmenu ()
{
int ret, quit = 0;
u8 *temp;
gui_menu *m = &menu_audio;
gui_item *items = m->items;
float fm_volume = (float)config.fm_preamp/100.0;
float psg_volume = (float)config.psg_preamp/100.0;
int offset = update_snd_items();
GUI_InitMenu(m);
if (config.filter == 1)
m->max_items = 6;
else if (config.filter == 2)
m->max_items = 10;
else
m->max_items = 5;
GUI_SlideMenuTitle(m,strlen("Audio "));
while (quit == 0)
{
ret = GUI_RunMenu(m);
/* special case */
if (config.hq_fm)
{
if (ret == 1)
{
GUI_OptionBox(m,0,"FM Roll-off",(void *)&config.rolloff,0.001,0.800,1.000,0);
sprintf (items[1].text, "FM Roll-off: %1.3f",config.rolloff);
ret = 255;
if (cart.romsize)
{
/* save YM2612 context */
temp = memalign(32,YM2612GetContextSize());
if (temp)
{
/* save YM2612 context */
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
/* reinitialize audio timings */
audio_init(snd.sample_rate,snd.frame_rate);
sound_init();
/* restore YM2612 context */
YM2612Restore(temp);
free(temp);
}
}
}
else if (ret > 1)
{
ret--;
}
}
switch (ret)
{
case 0:
config.hq_fm ^= 1;
sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
offset = update_snd_items();
if (cart.romsize)
{
/* save YM2612 context */
unsigned char *temp = memalign(32,YM2612GetContextSize());
if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
temp = memalign(32,YM2612GetContextSize());
if (temp)
{
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
}
/* reinitialize audio timings */
audio_init(snd.sample_rate,snd.frame_rate);
@ -758,92 +853,119 @@ static void soundmenu ()
break;
case 1:
config.psgBoostNoise ^= 1;
sprintf (items[1].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
SN76489_BoostNoise(config.psgBoostNoise);
config.dac_bits++;
if (config.dac_bits > 14)
config.dac_bits = 7;
if (config.dac_bits < 14)
sprintf (items[offset].text, "FM Resolution: %d bits", config.dac_bits);
else
sprintf (items[offset].text, "FM Resolution: MAX");
if (cart.romsize)
{
/* save YM2612 context */
temp = memalign(32,YM2612GetContextSize());
if (temp)
{
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
}
/* reinitialize audio timings */
audio_init(snd.sample_rate,snd.frame_rate);
sound_init();
/* restore YM2612 context */
if (temp)
{
YM2612Restore(temp);
free(temp);
}
}
break;
case 2:
GUI_OptionBox(m,0,"PSG Volume",(void *)&psg_volume,0.01,0.0,5.0,0);
sprintf (items[2].text, "PSG Volume: %1.2f", psg_volume);
config.psg_preamp = (int)(psg_volume * 100.0);
break;
case 3:
GUI_OptionBox(m,0,"FM Volume",(void *)&fm_volume,0.01,0.0,5.0,0);
sprintf (items[3].text, "FM Volume: %1.2f", fm_volume);
sprintf (items[offset+1].text, "FM Volume: %1.2f", fm_volume);
config.fm_preamp = (int)(fm_volume * 100.0);
break;
case 3:
GUI_OptionBox(m,0,"PSG Volume",(void *)&psg_volume,0.01,0.0,5.0,0);
sprintf (items[offset+2].text, "PSG Volume: %1.2f", psg_volume);
config.psg_preamp = (int)(psg_volume * 100.0);
break;
case 4:
config.filter ++;
if (config.filter > 2) config.filter = 0;
if (config.filter == 2)
{
m->max_items = 10;
sprintf (items[4].text, "Filtering: 3-BAND EQ");
sprintf (items[5].text, "Low Gain: %1.2f", config.lg);
strcpy (items[5].comment, "Adjust EQ Low Band Gain");
sprintf (items[6].text, "Middle Gain: %1.2f", config.mg);
sprintf (items[7].text, "High Gain: %1.2f", config.hg);
sprintf (items[8].text, "Low Freq: %d", config.low_freq);
sprintf (items[9].text, "High Freq: %d", config.high_freq);
}
else if (config.filter == 1)
{
m->max_items = 6;
sprintf (items[4].text, "Filtering: LOW PASS");
sprintf (items[5].text, "Low-Pass Rate: %d %%", config.lp_range);
strcpy (items[5].comment, "Adjust Low Pass filter");
}
else
{
sprintf (items[4].text, "Filtering: OFF");
m->max_items = 5;
m->offset = 1;
m->selected = 3;
}
/* reintialize EQ */
audio_set_equalizer();
config.psgBoostNoise ^= 1;
sprintf (items[offset+3].text, "PSG Noise Boost: %s", config.psgBoostNoise ? "ON":"OFF");
SN76489_BoostNoise(config.psgBoostNoise);
break;
case 5:
if (config.filter == 1)
config.filter = (config.filter + 1) % 3;
if (config.filter == 2)
{
GUI_OptionBox(m,0,"Low-Pass Rate",(void *)&config.lp_range,1,0,100,1);
sprintf (items[5].text, "Low-Pass Rate: %d %%", config.lp_range);
sprintf (items[offset+4].text, "Filtering: 3-BAND EQ");
sprintf (items[offset+5].text, "Low Gain: %1.2f", config.lg);
strcpy (items[offset+5].comment, "Adjust EQ Low Band Gain");
m->max_items = offset + 10;
audio_set_equalizer();
}
else if (config.filter == 1)
{
sprintf (items[offset+4].text, "Filtering: LOW-PASS");
sprintf (items[offset+5].text, "Low-Pass Rate: %d %%", config.lp_range);
strcpy (items[offset+5].comment, "Adjust Low Pass filter");
m->max_items = offset + 6;
}
else
{
GUI_OptionBox(m,0,"Low Gain",(void *)&config.lg,0.01,0.0,2.0,0);
sprintf (items[5].text, "Low Gain: %1.2f", config.lg);
audio_set_equalizer();
sprintf (items[offset+4].text, "Filtering: OFF");
m->max_items = offset + 5;
}
while ((m->offset + 4) > m->max_items)
{
m->offset --;
m->selected++;
}
break;
case 6:
GUI_OptionBox(m,0,"Middle Gain",(void *)&config.mg,0.01,0.0,2.0,0);
sprintf (items[6].text, "Middle Gain: %1.2f", config.mg);
if (config.filter == 1)
{
GUI_OptionBox(m,0,"Low-Pass Rate",(void *)&config.lp_range,1,0,100,1);
sprintf (items[offset+5].text, "Low-Pass Rate: %d %%", config.lp_range);
}
else
{
GUI_OptionBox(m,0,"Low Gain",(void *)&config.lg,0.01,0.0,2.0,0);
sprintf (items[offset+5].text, "Low Gain: %1.2f", config.lg);
audio_set_equalizer();
}
break;
case 7:
GUI_OptionBox(m,0,"High Gain",(void *)&config.hg,0.01,0.0,2.0,0);
sprintf (items[7].text, "High Gain: %1.2f", config.hg);
GUI_OptionBox(m,0,"Middle Gain",(void *)&config.mg,0.01,0.0,2.0,0);
sprintf (items[offset+6].text, "Middle Gain: %1.2f", config.mg);
audio_set_equalizer();
break;
case 8:
GUI_OptionBox(m,0,"Low Frequency",(void *)&config.low_freq,10,0,config.high_freq,1);
sprintf (items[8].text, "Low Freq: %d", config.low_freq);
GUI_OptionBox(m,0,"High Gain",(void *)&config.hg,0.01,0.0,2.0,0);
sprintf (items[offset+7].text, "High Gain: %1.2f", config.hg);
audio_set_equalizer();
break;
case 9:
GUI_OptionBox(m,0,"Low Frequency",(void *)&config.low_freq,10,0,config.high_freq,1);
sprintf (items[offset+8].text, "Low Freq: %d", config.low_freq);
audio_set_equalizer();
break;
case 10:
GUI_OptionBox(m,0,"High Frequency",(void *)&config.high_freq,100,config.low_freq,30000,1);
sprintf (items[9].text, "High Freq: %d", config.high_freq);
sprintf (items[offset+9].text, "High Freq: %d", config.high_freq);
audio_set_equalizer();
break;
@ -853,7 +975,6 @@ static void soundmenu ()
}
}
m->max_items = 10;
GUI_DeleteMenu(m);
}
@ -863,8 +984,9 @@ static void soundmenu ()
****************************************************************************/
static void systemmenu ()
{
int ret = 255;
int quit = 0;
int ret, quit = 0;
float framerate;
u8 *temp;
gui_menu *m = &menu_system;
gui_item *items = m->items;
@ -900,7 +1022,6 @@ static void systemmenu ()
else
{
m->max_items = 6;
if (m->offset > 2) m->offset--;
}
GUI_InitMenu(m);
@ -914,7 +1035,6 @@ static void systemmenu ()
{
case 0: /*** Region Force ***/
config.region_detect = (config.region_detect + 1) % 4;
if (config.region_detect == 0)
sprintf (items[0].text, "Console Region: AUTO");
else if (config.region_detect == 1)
@ -930,14 +1050,13 @@ static void systemmenu ()
set_region();
/* update framerate */
float framerate;
if (vdp_pal)
framerate = 50.0;
else
framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0;
/* save YM2612 context */
unsigned char *temp = memalign(32,YM2612GetContextSize());
temp = memalign(32,YM2612GetContextSize());
if (temp)
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
@ -1000,7 +1119,6 @@ static void systemmenu ()
sprintf (items[4].text, "Lock-On: SONIC & KNUCKLES");
else
sprintf (items[4].text, "Lock-On: OFF");
if (cart.romsize)
{
system_reset(); /* clear any patches first */
@ -1015,7 +1133,7 @@ static void systemmenu ()
sprintf (items[5].text, "Cartridge Swap: %s", config.hot_swap ? "ON":"OFF");
break;
case 6: /*** SVP emulation ***/
case 6: /*** SVP cycles per line ***/
GUI_OptionBox(m,0,"SVP Cycles",(void *)&SVP_cycles,1,1,1500,1);
sprintf (items[6].text, "SVP Cycles: %d", SVP_cycles);
break;
@ -1033,10 +1151,23 @@ static void systemmenu ()
* Video Settings menu
*
****************************************************************************/
#ifdef HW_RVL
#define VI_OFFSET 5
static void update_gamma(void)
{
VIDEO_SetGamma((int)(config.gamma * 10.0));
VIDEO_Flush();
}
#else
#define VI_OFFSET 3
#endif
static void videomenu ()
{
u16 state[2];
int ret, quit = 0;
float framerate;
u8 *temp;
gui_menu *m = &menu_video;
gui_item *items = m->items;
@ -1054,40 +1185,45 @@ static void videomenu ()
else
sprintf (items[1].text, "TV Mode: 50/60HZ");
sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
sprintf (items[2].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);
#endif
if (config.ntsc == 1)
sprintf (items[3].text, "NTSC Filter: COMPOSITE");
sprintf (items[VI_OFFSET].text, "NTSC Filter: COMPOSITE");
else if (config.ntsc == 2)
sprintf (items[3].text, "NTSC Filter: S-VIDEO");
sprintf (items[VI_OFFSET].text, "NTSC Filter: S-VIDEO");
else if (config.ntsc == 3)
sprintf (items[3].text, "NTSC Filter: RGB");
sprintf (items[VI_OFFSET].text, "NTSC Filter: RGB");
else
sprintf (items[3].text, "NTSC Filter: OFF");
sprintf (items[VI_OFFSET].text, "NTSC Filter: OFF");
sprintf (items[4].text, "Borders: %s", config.overscan ? "ON" : "OFF");
sprintf (items[VI_OFFSET+1].text, "Borders: %s", config.overscan ? "ON" : "OFF");
if (config.aspect == 1)
sprintf (items[5].text,"Aspect: ORIGINAL (4:3)");
sprintf (items[VI_OFFSET+2].text,"Aspect: ORIGINAL (4:3)");
else if (config.aspect == 2)
sprintf (items[5].text, "Aspect: ORIGINAL (16:9)");
sprintf (items[VI_OFFSET+2].text, "Aspect: ORIGINAL (16:9)");
else
sprintf (items[5].text, "Aspect: SCALE");
sprintf (items[VI_OFFSET+2].text, "Aspect: MANUAL SCALE");
sprintf (items[6].text, "Screen Position: (%s%02d,%s%02d)",
sprintf (items[VI_OFFSET+3].text, "Screen Position: (%s%02d,%s%02d)",
(config.xshift < 0) ? "":"+", config.xshift,
(config.yshift < 0) ? "":"+", config.yshift);
sprintf (items[7].text, "Screen Scaling: (%s%02d,%s%02d)",
sprintf (items[VI_OFFSET+4].text, "Screen Scaling: (%s%02d,%s%02d)",
(config.xscale < 0) ? "":"+", config.xscale,
(config.yscale < 0) ? "":"+", config.yscale);
GUI_InitMenu(m);
if (config.aspect)
m->max_items = 7;
m->max_items = VI_OFFSET+4;
else
m->max_items = 8;
m->max_items = VI_OFFSET+5;
GUI_InitMenu(m);
GUI_SlideMenuTitle(m,strlen("Video "));
while (quit == 0)
@ -1126,14 +1262,13 @@ static void videomenu ()
config.tv_mode = (config.tv_mode + 1) % 3;
/* update framerate */
float framerate;
if (vdp_pal)
framerate = 50.0;
else
framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0;
/* save YM2612 context */
unsigned char *temp = memalign(32,YM2612GetContextSize());
temp = memalign(32,YM2612GetContextSize());
if (temp)
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
@ -1161,58 +1296,94 @@ static void videomenu ()
}
break;
case 2: /*** bilinear filtering ***/
case 2: /*** GX Texture filtering ***/
config.bilinear ^= 1;
sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
sprintf (items[2].text, "GX Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
break;
case 3: /*** NTSC filter ***/
#ifdef HW_RVL
case 3: /*** VIDEO Trap filtering ***/
config.trap ^= 1;
sprintf (items[3].text, "VI Trap Filter: %s", config.trap ? " ON" : "OFF");
break;
case 4: /*** VIDEO Gamma correction ***/
if (cart.romsize)
{
update_gamma();
state[0] = m->arrows[0]->state;
state[1] = m->arrows[1]->state;
m->max_buttons = 0;
m->max_images = 0;
m->arrows[0]->state = 0;
m->arrows[1]->state = 0;
m->screenshot = 255;
strcpy(m->title,"");
GUI_OptionBox(m,update_gamma,"VI Gamma Correction",(void *)&config.gamma,0.1,0.1,3.0,0);
m->max_buttons = 4;
m->max_images = 6;
m->arrows[0]->state = state[0];
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);
VIDEO_SetGamma(VI_GM_1_0);
VIDEO_Flush();
}
else
{
GUI_WaitPrompt("Error","Please load a game first !\n");
}
break;
#endif
case VI_OFFSET: /*** NTSC filter ***/
config.ntsc = (config.ntsc + 1) % 4;
if (config.ntsc == 1)
sprintf (items[3].text, "NTSC Filter: COMPOSITE");
sprintf (items[VI_OFFSET].text, "NTSC Filter: COMPOSITE");
else if (config.ntsc == 2)
sprintf (items[3].text, "NTSC Filter: S-VIDEO");
sprintf (items[VI_OFFSET].text, "NTSC Filter: S-VIDEO");
else if (config.ntsc == 3)
sprintf (items[3].text, "NTSC Filter: RGB");
sprintf (items[VI_OFFSET].text, "NTSC Filter: RGB");
else
sprintf (items[3].text, "NTSC Filter: OFF");
sprintf (items[VI_OFFSET].text, "NTSC Filter: OFF");
break;
case 4: /*** overscan emulation ***/
case VI_OFFSET+1: /*** overscan emulation ***/
config.overscan ^= 1;
sprintf (items[4].text, "Borders: %s", config.overscan ? "ON" : "OFF");
sprintf (items[VI_OFFSET+1].text, "Borders: %s", config.overscan ? "ON" : "OFF");
break;
case 5: /*** aspect ratio ***/
case VI_OFFSET+2: /*** aspect ratio ***/
config.aspect = (config.aspect + 1) % 3;
if (config.aspect == 1)
sprintf (items[5].text,"Aspect: ORIGINAL (4:3)");
sprintf (items[VI_OFFSET+2].text,"Aspect: ORIGINAL (4:3)");
else if (config.aspect == 2)
sprintf (items[5].text, "Aspect: ORIGINAL (16:9)");
sprintf (items[VI_OFFSET+2].text, "Aspect: ORIGINAL (16:9)");
else
sprintf (items[5].text, "Aspect: SCALED");
sprintf (items[VI_OFFSET+2].text, "Aspect: MANUAL SCALE");
if (config.aspect)
{
/* disable items */
m->max_items = 7;
m->max_items = VI_OFFSET+4;
/* reset menu selection */
if (m->offset > 3)
if (m->offset > VI_OFFSET)
{
m->offset = 3;
m->offset = VI_OFFSET;
m->selected = 2;
}
}
else
{
/* enable items */
m->max_items = 8;
m->max_items = VI_OFFSET+5;
}
break;
case 6: /*** screen position ***/
case VI_OFFSET+3: /*** screen position ***/
if (cart.romsize)
{
state[0] = m->arrows[0]->state;
@ -1230,7 +1401,7 @@ static void videomenu ()
m->arrows[1]->state = state[1];
m->screenshot = 0;
strcpy(m->title,"Video Settings");
sprintf (items[6].text, "Screen Position: (%s%02d,%s%02d)",
sprintf (items[VI_OFFSET+3].text, "Screen Position: (%s%02d,%s%02d)",
(config.xshift < 0) ? "":"+", config.xshift,
(config.yshift < 0) ? "":"+", config.yshift);
}
@ -1240,7 +1411,7 @@ static void videomenu ()
}
break;
case 7: /*** screen scaling ***/
case VI_OFFSET+4: /*** screen scaling ***/
if (cart.romsize)
{
state[0] = m->arrows[0]->state;
@ -1258,7 +1429,7 @@ static void videomenu ()
m->arrows[1]->state = state[1];
m->screenshot = 0;
strcpy(m->title,"Video Settings");
sprintf (items[7].text, "Screen Scaling: (%s%02d,%s%02d)",
sprintf (items[VI_OFFSET+4].text, "Screen Scaling: (%s%02d,%s%02d)",
(config.xscale < 0) ? "":"+", config.xscale,
(config.yscale < 0) ? "":"+", config.yscale);
}
@ -1274,7 +1445,6 @@ static void videomenu ()
}
}
m->max_items = 8;
GUI_DeleteMenu(m);
}
@ -1548,7 +1718,7 @@ static void ctrlmenu(void)
m->buttons[9].shift[3] = 0;
/* update title */
strcpy(m->title,"Controller Settings");
sprintf(m->title,"Controller Settings");
}
break;
@ -1600,7 +1770,7 @@ static void ctrlmenu(void)
m->buttons[9].shift[3] = 0;
/* update title */
strcpy(m->title,"Controller Settings");
sprintf(m->title,"Controller Settings");
}
break;
@ -1900,6 +2070,9 @@ static void ctrlmenu(void)
/* update selector */
m->selected -= m->buttons[m->selected].shift[2];
/* restore title */
sprintf(m->title,"Controller Settings");
/* stay in menu */
update = 0;
}
@ -1960,9 +2133,6 @@ static void ctrlmenu(void)
m->buttons[8].shift[3] = 0;
m->buttons[9].shift[3] = 0;
/* clear menu title */
strcpy(m->title,"Controller Settings");
/* clear menu items */
memset(&m->items[0],0,sizeof(gui_item));
memset(&m->items[1],0,sizeof(gui_item));

View File

@ -367,6 +367,7 @@ static void gxStart(void)
GX_Init(&gp_fifo, DEFAULT_FIFO_SIZE);
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
GX_SetCullMode(GX_CULL_NONE);
GX_SetClipMode(GX_CLIP_DISABLE);
GX_SetDispCopyGamma(GX_GM_1_0);
GX_SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
GX_SetColorUpdate(GX_TRUE);
@ -426,18 +427,21 @@ static void gxResetRendering(u8 type)
GX_Flush();
}
/* Reset GX 2D rendering */
static void gxResetView(GXRModeObj *tvmode)
/* Reset GX rendering mode */
static void gxResetMode(GXRModeObj *tvmode)
{
Mtx44 p;
f32 yScale = GX_GetYScaleFactor(tvmode->efbHeight, tvmode->xfbHeight);
u16 xfbHeight = GX_SetDispCopyYScale(yScale);
u16 xfbWidth = tvmode->fbWidth;
if (xfbWidth & 15) // xfb width is 16 pixels aligned
xfbWidth = (xfbWidth & ~15) + 16;
GX_SetCopyClear((GXColor)BLACK,0x00ffffff);
GX_SetViewport(0.0F, 0.0F, tvmode->fbWidth, tvmode->efbHeight, 0.0F, 1.0F);
GX_SetScissor(0, 0, tvmode->fbWidth, tvmode->efbHeight);
GX_SetDispCopySrc(0, 0, tvmode->fbWidth, tvmode->efbHeight);
GX_SetDispCopyDst(tvmode->fbWidth, xfbHeight);
GX_SetDispCopyDst(xfbWidth, xfbHeight);
GX_SetCopyFilter(tvmode->aa, tvmode->sample_pattern, (tvmode->xfbMode == VI_XFBMODE_SF) ? GX_FALSE : GX_TRUE, tvmode->vfilter);
GX_SetFieldMode(tvmode->field_rendering, ((tvmode->viHeight == 2 * tvmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
guOrtho(p, tvmode->efbHeight/2, -(tvmode->efbHeight/2), -(tvmode->fbWidth/2), tvmode->fbWidth/2, 100, 1000);
@ -497,42 +501,56 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
/* Reset GX/VI hardware scaler */
static void gxResetScaler(u32 width, u32 height)
{
/* get Aspect Ratio (depends on current configuration) */
int xscale,yscale;
int xscale = 0;
int yscale = 0;
int offset = 0;
/* retrieve screen aspect ratio */
gxSetAspectRatio(&xscale, &yscale);
/* GX horizontal scaling (done during EFB rendering) */
/* by default, use maximal EFB width */
/* default EFB width */
rmode->fbWidth = 640;
/* no filtering, disable GX horizontal scaling */
if (!config.bilinear && !config.ntsc)
{
/* filtering (soft or hard) is disabled, let VI handles horizontal scaling */
if ((width * 2) <= 640)
rmode->fbWidth = width * 2; /* GX scaling enabled (simple doubler) */
rmode->fbWidth = width * 2;
else if (width <= 640)
rmode->fbWidth = width; /* GX scaling disabled */
rmode->fbWidth = width;
}
/* VI horizontal scaling (done during EFB->XFB copy) */
int offset = 0;
/* configure VI width */
if ((xscale * 2) > rmode->fbWidth)
{
/* max width = 720 pixels */
if (xscale > 360)
{
/* save offset for later */
offset = xscale - 360;
offset = ((xscale - 360) * rmode->fbWidth) / rmode->viWidth;
/* maximal width */
xscale = 360;
}
/* VI horizontal scaling is enabled */
/* enable VI upscaling */
rmode->viWidth = xscale * 2;
rmode->viXOrigin = (720 - (xscale * 2)) / 2;
/* update GX horizontal scaling (disabled if no offset) */
xscale = (rmode->fbWidth / 2) + ((offset * rmode->fbWidth) / rmode->viWidth);
/* default GX horizontal scaling */
xscale = (rmode->fbWidth / 2);
/* handle additional upscaling */
if (offset)
{
/* no filtering, reduce EFB width to increase VI upscaling */
if (!config.bilinear && !config.ntsc)
rmode->fbWidth -= (offset * 2);
/* increase GX horizontal scaling */
else
xscale += offset;
}
}
else
{
@ -547,9 +565,7 @@ static void gxResetScaler(u32 width, u32 height)
/* Configure GX vertical scaling (480i/576i/480p) */
if (config.render)
{
yscale = yscale * 2;
}
/* Set GX scaler (Vertex Position matrix) */
square[6] = square[3] = xshift + xscale;
@ -1256,18 +1272,24 @@ void gx_video_Stop(void)
gxTextureClose(&crosshair[0]);
gxTextureClose(&crosshair[1]);
/* reset GX */
/* GX menu rendering */
gxResetRendering(1);
gxResetView(vmode);
gxResetMode(vmode);
/* VSYNC default callbacks */
/* default VI settings */
VIDEO_SetPreRetraceCallback(NULL);
VIDEO_SetPostRetraceCallback(gx_input_UpdateMenu);
#ifdef HW_RVL
VIDEO_SetTrapFilter(1);
VIDEO_SetGamma(VI_GM_1_0);
#endif
/* reset VI & adjust overscan */
/* default TV mode */
vmode->viWidth = config.screen_w;
vmode->viXOrigin = (VI_MAX_WIDTH_NTSC - vmode->viWidth)/2;
VIDEO_Configure(vmode);
/* starts menu rendering */
gxDrawScreenshot(0xff);
gxSetScreen();
}
@ -1281,6 +1303,11 @@ void gx_video_Start(void)
else
gc_pal = 0;
#ifdef HW_RVL
VIDEO_SetTrapFilter(config.trap);
VIDEO_SetGamma((int)(config.gamma * 10.0));
#endif
/* VSYNC callbacks */
/* in 60hz mode, frame emulation is synchronized with Video Interrupt */
if (!gc_pal && !vdp_pal)
@ -1288,7 +1315,7 @@ void gx_video_Start(void)
VIDEO_SetPostRetraceCallback(NULL);
VIDEO_Flush();
/* switch interlaced/progressive video settings */
/* set interlaced or progressive video mode */
if (config.render == 2)
{
tvmodes[2]->viTVMode = VI_TVMODE_NTSC_PROG;
@ -1300,7 +1327,7 @@ void gx_video_Start(void)
tvmodes[2]->xfbMode = VI_XFBMODE_DF;
}
/* overscan */
/* overscan emulation */
if (config.overscan)
{
bitmap.viewport.x = (reg[12] & 1) ? 16 : 12;
@ -1347,10 +1374,10 @@ void gx_video_Start(void)
if (config.gun_cursor[1] && (input.dev[5] == DEVICE_LIGHTGUN))
crosshair[1] = gxTextureOpenPNG(Crosshair_p2_png,0);
/* apply changes on next video update */
/* force changes on next video update */
bitmap.viewport.changed = 1;
/* reset GX rendering */
/* GX emulation rendering */
gxResetRendering(0);
/* resynchronize emulation with VSYNC*/
@ -1375,9 +1402,11 @@ void gx_video_Update(void)
if (vwidth != old_vwidth)
return;
/* special cases */
/* interlaced mode */
if (config.render && interlaced)
vheight = vheight << 1;
/* ntsc filter */
if (config.ntsc)
vwidth = (reg[12]&1) ? MD_NTSC_OUT_WIDTH(vwidth) : SMS_NTSC_OUT_WIDTH(vwidth);
@ -1396,19 +1425,19 @@ void gx_video_Update(void)
/* load texture object */
GX_LoadTexObj(&texobj, GX_TEXMAP0);
/* reset TV mode */
/* update TV mode */
if (config.render)
rmode = tvmodes[gc_pal*3 + 2];
else
rmode = tvmodes[gc_pal*3 + interlaced];
/* reset aspect ratio */
/* update aspect ratio */
gxResetScaler(vwidth,vheight);
/* reset GX */
gxResetView(rmode);
/* update GX rendering mode */
gxResetMode(rmode);
/* change VI mode */
/* update VI mode */
VIDEO_Configure(rmode);
VIDEO_Flush();
}
@ -1548,7 +1577,7 @@ void gx_video_Init(void)
/* Initialize GX */
gxStart();
gxResetRendering(1);
gxResetView(vmode);
gxResetMode(vmode);
/* initialize FONT */
if (!FONT_Init())

View File

@ -33,9 +33,9 @@
#define SK_UPMEM "/genplus/sk2chip.bin"
#ifdef HW_RVL
#define VERSION "version 1.3.2W"
#define VERSION "version 1.4.0W"
#else
#define VERSION "version 1.3.2G"
#define VERSION "version 1.4.0G"
#endif
#define osd_input_Update() gx_input_UpdateEmu()

547
source/gx/vi_encoder.c Normal file
View File

@ -0,0 +1,547 @@
/****************************************************************************
* vi_encoder.c
*
* Wii Audio/Video Encoder support
*
* Copyright (C) 2009 Hector Martin (marcan)
* Additional code by Eke-Eke
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/
#if defined(HW_RVL)
#include <string.h>
#include <gccore.h>
#include <ogcsys.h>
#include <ogc/machine/processor.h>
/****************************************************************************
* I2C driver by Hector Martin (marcan)
*
****************************************************************************/
#define _SHIFTL(v, s, w) \
((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
#define _SHIFTR(v, s, w) \
((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
extern void udelay(int us);
static u32 i2cIdentFirst = 0;
static u32 i2cIdentFlag = 1;
static vu16* const _viReg = (u16*)0xCC002000;
static vu32* const _i2cReg = (u32*)0xCD800000;
static inline void __viOpenI2C(u32 channel)
{
u32 val = ((_i2cReg[49]&~0x8000)|0x4000);
val |= _SHIFTL(channel,15,1);
_i2cReg[49] = val;
}
static inline u32 __viSetSCL(u32 channel)
{
u32 val = (_i2cReg[48]&~0x4000);
val |= _SHIFTL(channel,14,1);
_i2cReg[48] = val;
return 1;
}
static inline u32 __viSetSDA(u32 channel)
{
u32 val = (_i2cReg[48]&~0x8000);
val |= _SHIFTL(channel,15,1);
_i2cReg[48] = val;
return 1;
}
static inline u32 __viGetSDA()
{
return _SHIFTR(_i2cReg[50],15,1);
}
static inline void __viCheckI2C()
{
__viOpenI2C(0);
udelay(4);
i2cIdentFlag = 0;
if(__viGetSDA()!=0) i2cIdentFlag = 1;
}
static u32 __sendSlaveAddress(u8 addr)
{
u32 i;
__viSetSDA(i2cIdentFlag^1);
udelay(2);
__viSetSCL(0);
for(i=0;i<8;i++) {
if(addr&0x80) __viSetSDA(i2cIdentFlag);
else __viSetSDA(i2cIdentFlag^1);
udelay(2);
__viSetSCL(1);
udelay(2);
__viSetSCL(0);
addr <<= 1;
}
__viOpenI2C(0);
udelay(2);
__viSetSCL(1);
udelay(2);
if(i2cIdentFlag==1 && __viGetSDA()!=0) return 0;
__viSetSDA(i2cIdentFlag^1);
__viOpenI2C(1);
__viSetSCL(0);
return 1;
}
static u32 __VISendI2CData(u8 addr,void *val,u32 len)
{
u8 c;
s32 i,j;
u32 level,ret;
if(i2cIdentFirst==0) {
__viCheckI2C();
i2cIdentFirst = 1;
}
_CPU_ISR_Disable(level);
__viOpenI2C(1);
__viSetSCL(1);
__viSetSDA(i2cIdentFlag);
udelay(4);
ret = __sendSlaveAddress(addr);
if(ret==0) {
_CPU_ISR_Restore(level);
return 0;
}
__viOpenI2C(1);
for(i=0;i<len;i++) {
c = ((u8*)val)[i];
for(j=0;j<8;j++) {
if(c&0x80) __viSetSDA(i2cIdentFlag);
else __viSetSDA(i2cIdentFlag^1);
udelay(2);
__viSetSCL(1);
udelay(2);
__viSetSCL(0);
c <<= 1;
}
__viOpenI2C(0);
udelay(2);
__viSetSCL(1);
udelay(2);
if(i2cIdentFlag==1 && __viGetSDA()!=0) {
_CPU_ISR_Restore(level);
return 0;
}
__viSetSDA(i2cIdentFlag^1);
__viOpenI2C(1);
__viSetSCL(0);
}
__viOpenI2C(1);
__viSetSDA(i2cIdentFlag^1);
udelay(2);
__viSetSDA(i2cIdentFlag);
_CPU_ISR_Restore(level);
return 1;
}
static void __VIWriteI2CRegister8(u8 reg, u8 data)
{
u8 buf[2];
buf[0] = reg;
buf[1] = data;
__VISendI2CData(0xe0,buf,2);
udelay(2);
}
static void __VIWriteI2CRegister16(u8 reg, u16 data)
{
u8 buf[3];
buf[0] = reg;
buf[1] = data >> 8;
buf[2] = data & 0xFF;
__VISendI2CData(0xe0,buf,3);
udelay(2);
}
static void __VIWriteI2CRegister32(u8 reg, u32 data)
{
u8 buf[5];
buf[0] = reg;
buf[1] = data >> 24;
buf[2] = (data >> 16) & 0xFF;
buf[3] = (data >> 8) & 0xFF;
buf[4] = data & 0xFF;
__VISendI2CData(0xe0,buf,5);
udelay(2);
}
static void __VIWriteI2CRegisterBuf(u8 reg, int size, u8 *data)
{
u8 buf[0x100];
buf[0] = reg;
memcpy(&buf[1], data, size);
__VISendI2CData(0xe0,buf,size+1);
udelay(2);
}
/****************************************************************************
* A/V functions support (Eke-Eke)
*
****************************************************************************/
static const u8 gamma_coeffs[][33] =
{
/* GM_0_0 */
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
/* GM_0_1 */
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x97, 0x3B, 0x49,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x80, 0x1B, 0x80, 0xEB, 0x00
},
/* GM_0_2 */
{
0x00, 0x00, 0x00, 0x28, 0x00, 0x5A, 0x02, 0xDB, 0x0D, 0x8D, 0x30, 0x49,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x10, 0x00, 0x10, 0x40, 0x11, 0x00, 0x18, 0x80, 0x42, 0x00, 0xEB, 0x00
},
/* GM_0_3 */
{
0x00, 0x00, 0x00, 0x7A, 0x02, 0x3C, 0x07, 0x6D, 0x12, 0x9C, 0x27, 0x24,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x10, 0x00, 0x10, 0xC0, 0x15, 0x80, 0x29, 0x00, 0x62, 0x00, 0xEB, 0x00
},
/* GM_0_4 */
{
0x00, 0x4E, 0x01, 0x99, 0x05, 0x2D, 0x0B, 0x24, 0x14, 0x29, 0x20, 0xA4,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x00, 0x10, 0x10, 0x40, 0x12, 0xC0, 0x1D, 0xC0, 0x3B, 0x00, 0x78, 0xC0, 0xEB, 0x00
},
/* GM_0_5 */
{
0x00, 0xEC, 0x03, 0xD7, 0x08, 0x00, 0x0D, 0x9E, 0x14, 0x3E, 0x1B, 0xDB,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x10, 0xC0, 0x16, 0xC0, 0x27, 0xC0, 0x4B, 0x80, 0x89, 0x80, 0xEB, 0x00
},
/* GM_0_6 */
{
0x02, 0x76, 0x06, 0x66, 0x0A, 0x96, 0x0E, 0xF3, 0x13, 0xAC, 0x18, 0x49,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x12, 0x00, 0x1C, 0x00, 0x32, 0x80, 0x59, 0xC0, 0x96, 0x00, 0xEB, 0x00
},
/* GM_0_7 */
{
0x04, 0xEC, 0x08, 0xF5, 0x0C, 0x96, 0x0F, 0xCF, 0x12, 0xC6, 0x15, 0x80,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x14, 0x00, 0x22, 0x00, 0x3C, 0xC0, 0x66, 0x40, 0x9F, 0xC0, 0xEB, 0x00
},
/* GM_0_8 */
{
0x08, 0x00, 0x0B, 0xAE, 0x0E, 0x00, 0x10, 0x30, 0x11, 0xCB, 0x13, 0x49,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x16, 0x80, 0x28, 0xC0, 0x46, 0x80, 0x71, 0x00, 0xA7, 0x80, 0xEB, 0x00
},
/* GM_0_9 */
{
0x0B, 0xB1, 0x0E, 0x14, 0x0F, 0x2D, 0x10, 0x18, 0x10, 0xE5, 0x11, 0x80,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x19, 0x80, 0x2F, 0x80, 0x4F, 0xC0, 0x7A, 0x00, 0xAD, 0xC0, 0xEB, 0x00
},
/* GM_1_0 */
{
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00,
0x10, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xEB,
0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x60, 0x00, 0x80, 0x00, 0xA0, 0x00, 0xEB, 0x00
},
/* GM_1_1 */
{
0x14, 0xEC, 0x11, 0xC2, 0x10, 0x78, 0x0F, 0xB6, 0x0F, 0x2F, 0x0E, 0xB6,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x21, 0x00, 0x3C, 0xC0, 0x5F, 0xC0, 0x89, 0x00, 0xB7, 0x80, 0xEB, 0x00
},
/* GM_1_2 */
{
0x19, 0xD8, 0x13, 0x33, 0x10, 0xD2, 0x0F, 0x6D, 0x0E, 0x5E, 0x0D, 0xA4,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x25, 0x00, 0x43, 0x00, 0x66, 0xC0, 0x8F, 0x40, 0xBB, 0x40, 0xEB, 0x00
},
/* GM_1_3 */
{
0x1E, 0xC4, 0x14, 0x7A, 0x11, 0x0F, 0xF, 0x0C, 0x0D, 0xA1, 0x0C, 0xB6,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x29, 0x00, 0x49, 0x00, 0x6D, 0x40, 0x94, 0xC0, 0xBE, 0x80, 0xEB, 0x00
},
/* GM_1_4 */
{
0x24, 0x00, 0x15, 0x70, 0x11, 0x0F, 0x0E, 0xAA, 0x0D, 0x0F, 0x0B, 0xDB,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x2D, 0x40, 0x4E, 0xC0, 0x73, 0x00, 0x99, 0x80, 0xC1, 0x80, 0xEB, 0x00
},
/* GM_1_5 */
{
0x29, 0x3B, 0x16, 0x3D, 0x11, 0x0F, 0x0E, 0x30, 0x0C, 0x7D, 0x0B, 0x24,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x31, 0x80, 0x54, 0x40, 0x78, 0x80, 0x9D, 0xC0, 0xC4, 0x00, 0xEB, 0x00
},
/* GM_1_6 */
{
0x2E, 0x27, 0x17, 0x0A, 0x10, 0xD2, 0x0D, 0xE7, 0x0B, 0xEB, 0x0A, 0x80,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x35, 0x80, 0x59, 0x80, 0x7D, 0x40, 0xA1, 0xC0, 0xC6, 0x40, 0xEB, 0x00
},
/* GM_1_7 */
{
0x33, 0x62, 0x17, 0x5C, 0x10, 0xD2, 0x0D, 0x6D, 0x0B, 0x6D, 0x09, 0xED,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x39, 0xC0, 0x5E, 0x40, 0x82, 0x00, 0xA5, 0x40, 0xC8, 0x40, 0xEB, 0x00
},
/* GM_1_8 */
{
0x38, 0x4E, 0x17, 0xAE, 0x10, 0xB4, 0x0D, 0x0C, 0x0A, 0xF0, 0x09, 0x6D,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x3D, 0xC0, 0x62, 0xC0, 0x86, 0x40, 0xA8, 0x80, 0xCA, 0x00, 0xEB, 0x00
},
/* GM_1_9 */
{
0x3D, 0x3B, 0x18, 0x00, 0x10, 0x5A, 0x0C, 0xC3, 0x0A, 0x72, 0x09, 0x00,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x41, 0xC0, 0x67, 0x40, 0x8A, 0x00, 0xAB, 0x80, 0xCB, 0x80, 0xEB, 0x00
},
/* GM_2_0 */
{
0x41, 0xD8, 0x18, 0x28, 0x10, 0x3C, 0x0C, 0x49, 0x0A, 0x1F, 0x08, 0x92,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x45, 0x80, 0x6B, 0x40, 0x8D, 0xC0, 0xAE, 0x00, 0xCD, 0x00, 0xEB, 0x00
},
/* GM_2_1 */
{
0x46, 0x76, 0x18, 0x51, 0x0F, 0xE1, 0x0C, 0x00, 0x09, 0xB6, 0x08, 0x36,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x49, 0x40, 0x6F, 0x40, 0x91, 0x00, 0xB0, 0x80, 0xCE, 0x40, 0xEB, 0x00
},
/* GM_2_2 */
{
0x4A, 0xC4, 0x18, 0x7A, 0x0F, 0xA5, 0x0B, 0x9E, 0x09, 0x63, 0x07, 0xDB,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x4C, 0xC0, 0x73, 0x00, 0x94, 0x40, 0xB2, 0xC0, 0xCF, 0x80, 0xEB, 0x00
},
/* GM_2_3 */
{
0x4F, 0x13, 0x18, 0x51, 0x0F, 0x69, 0x0B, 0x6D, 0x09, 0x0F, 0x07, 0x80,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x50, 0x40, 0x76, 0x40, 0x97, 0x00, 0xB5, 0x00, 0xD0, 0xC0, 0xEB, 0x00
},
/* GM_2_4 */
{
0x53, 0x13, 0x18, 0x7A, 0x0F, 0x0F, 0x0B, 0x24, 0x08, 0xBC, 0x07, 0x36,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x53, 0x80, 0x79, 0xC0, 0x99, 0xC0, 0xB7, 0x00, 0xD1, 0xC0, 0xEB, 0x00
},
/* GM_2_5 */
{
0x57, 0x13, 0x18, 0x51, 0x0E, 0xF0, 0x0A, 0xC3, 0x08, 0x7D, 0x06, 0xED,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x56, 0xC0, 0x7C, 0xC0, 0x9C, 0x80, 0xB8, 0xC0, 0xD2, 0xC0, 0xEB, 0x00
},
/* GM_2_6 */
{
0x5B, 0x13, 0x18, 0x28, 0x0E, 0x96, 0x0A, 0x92, 0x08, 0x29, 0x06, 0xB6,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x5A, 0x00, 0x7F, 0xC0, 0x9E, 0xC0, 0xBA, 0x80, 0xD3, 0x80, 0xEB, 0x00
},
/* GM_2_7 */
{
0x5E, 0xC4, 0x18, 0x00, 0x0E, 0x78, 0x0A, 0x30, 0x08, 0x00, 0x06, 0x6D,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x5D, 0x00, 0x82, 0x80, 0xA1, 0x40, 0xBC, 0x00, 0xD4, 0x80, 0xEB, 0x00
},
/* GM_2_8 */
{
0x62, 0x76, 0x17, 0xD7, 0x0E, 0x1E, 0x0A, 0x00, 0x07, 0xC1, 0x06, 0x36,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x60, 0x00, 0x85, 0x40, 0xA3, 0x40, 0xBD, 0x80, 0xD5, 0x40, 0xEB, 0x00
},
/* GM_2_9 */
{
0x65, 0xD8, 0x17, 0xAE, 0x0D, 0xE1, 0x09, 0xCF, 0x07, 0x82, 0x06, 0x00,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x62, 0xC0, 0x87, 0xC0, 0xA5, 0x40, 0xBF, 0x00, 0xD6, 0x00, 0xEB, 0x00
},
/* GM_3_0 */
{
0x69, 0x3B, 0x17, 0x85, 0x0D, 0xA5, 0x09, 0x86, 0x07, 0x43, 0x05, 0xDB,
0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
0x10, 0x00, 0x65, 0x80, 0x8A, 0x40, 0xA7, 0x40, 0xC0, 0x40, 0xD6, 0x80, 0xEB, 0x00
}
};
void __VISetTiming(u8 timing)
{
__VIWriteI2CRegister8(0x00,timing);
}
void __VISetYUVSEL(u8 dtvstatus)
{
u8 vdacFlagRegion = 0;
u32 currTvMode = _SHIFTR(_viReg[1],8,2);
if(currTvMode==VI_PAL || currTvMode==VI_EURGB60)
vdacFlagRegion = 2;
else if(currTvMode==VI_MPAL)
vdacFlagRegion = 1;
__VIWriteI2CRegister8(0x01, _SHIFTL(dtvstatus,5,3)|(vdacFlagRegion&0x1f));
}
void __VISetVBICtrl(u16 data)
{
__VIWriteI2CRegister16(0x02, data);
}
void __VISetTrapFilter(u8 disable)
{
if (disable)
__VIWriteI2CRegister8(0x03, 0);
else
__VIWriteI2CRegister8(0x03, 1);
}
void __VISet3in1Output(u8 enable)
{
__VIWriteI2CRegister8(0x04,enable);
}
void __VISetCGMS(u16 value)
{
__VIWriteI2CRegister16(0x05, value);
}
void __VISetWSS(u16 value)
{
__VIWriteI2CRegister16(0x08, value);
}
void __VISetRGBOverDrive(u8 value)
{
u32 currTvMode = _SHIFTR(_viReg[1],8,2);
if (currTvMode == VI_DEBUG)
__VIWriteI2CRegister8(0x0A,(value<<1)|1);
else
__VIWriteI2CRegister8(0x0A,0);
}
void __VISetOverSampling(void)
{
__VIWriteI2CRegister8(0x65,1);
}
void __VISetCCSEL(void)
{
__VIWriteI2CRegister8(0x6a,1);
}
void __VISetFilterEURGB60(u8 enable)
{
__VIWriteI2CRegister8(0x6e, enable);
}
void __VISetVolume(u16 value)
{
__VIWriteI2CRegister16(0x71,value);
}
void __VISetClosedCaption(u32 value)
{
__VIWriteI2CRegister32(0x7a, value);
}
void __VISetGamma(VIGamma gamma)
{
u8 *data = (u8 *)&gamma_coeffs[gamma][0];
__VIWriteI2CRegisterBuf(0x10, 0x21, data);
}
/* User Configurable */
void VIDEO_SetGamma(VIGamma gamma)
{
__VISetGamma(gamma);
}
void VIDEO_SetTrapFilter(bool enable)
{
if (enable)
__VISetTrapFilter(0);
else
__VISetTrapFilter(1);
}
#endif

29
source/gx/vi_encoder.h Normal file
View File

@ -0,0 +1,29 @@
/****************************************************************************
* vi_encoder.c
*
* Wii Audio/Video Encoder support
*
* Copyright (C) 2009 Hector Martin (marcan)
* Additional code by Eke-Eke
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***************************************************************************/
#if defined(HW_RVL)
extern void VIDEO_SetGamma(VIGamma gamma);
extern void VIDEO_SetTrapFilter(bool enable);
#endif

View File

@ -23,7 +23,7 @@ static int step = STEREO;
static int input_per_cycle;
static double ratio = 1.0;
static void gen_sinc(double rolloff, int width, double offset, double spacing, double scale, int count, short *out )
static void gen_sinc(double rolloff, int width, double offset, double spacing, double scale, int count, sample_t *out )
{
double w, rolloff_cos_a, num, den, sinc;
double const maxh = 256;
@ -138,7 +138,7 @@ void Fir_Resampler_clear()
}
}
double Fir_Resampler_time_ratio( double new_factor )
double Fir_Resampler_time_ratio( double new_factor, double rolloff )
{
ratio = new_factor;
@ -177,7 +177,7 @@ double Fir_Resampler_time_ratio( double new_factor )
for ( i = 0; i < res; i++ )
{
gen_sinc( ROLLOFF, (int) (WIDTH * filter + 1) & ~1, pos, filter,
gen_sinc( rolloff, (int) (WIDTH * filter + 1) & ~1, pos, filter,
(double) (0x7FFF * GAIN * filter),
(int) WIDTH, impulses[i] );

View File

@ -8,15 +8,14 @@
#define MAX_RES 32
#define WIDTH 16
#define WRITE_OFFSET (WIDTH * STEREO) - STEREO
#define ROLLOFF 0.990
#define GAIN 1.0
typedef short sample_t;
typedef long int sample_t;
extern int Fir_Resampler_initialize( int new_size );
extern void Fir_Resampler_shutdown( void );
extern void Fir_Resampler_clear( void );
extern double Fir_Resampler_time_ratio( double new_factor );
extern double Fir_Resampler_time_ratio( double new_factor, double rolloff );
extern double Fir_Resampler_ratio( void );
extern int Fir_Resampler_max_write( void );
extern sample_t* Fir_Resampler_buffer( void );

View File

@ -54,7 +54,7 @@ static inline void fm_update(unsigned int cycles)
}
/* select input sample buffer */
int16 *buffer = Fir_Resampler_buffer();
int32 *buffer = Fir_Resampler_buffer();
if (buffer)
{
Fir_Resampler_write(cnt << 1);
@ -139,7 +139,7 @@ void sound_init(void)
if (config.hq_fm)
{
fm_cycles_ratio = 144 * 7 * (1 << 11);
Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (144.0 * 7.0));
Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (144.0 * 7.0), config.rolloff);
}
#ifdef LOGSOUND

View File

@ -131,7 +131,6 @@
#include <math.h>
#include "shared.h"
#include "Fir_Resampler.h"
/* globals */
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
@ -164,10 +163,6 @@
#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
#define MAXOUT (+32767)
#define MINOUT (-32768)
/* TL_TAB_LEN is calculated as:
* 13 - sinus amplitude bits (Y axis)
* 2 - sinus sign bit (Y axis)
@ -1736,8 +1731,8 @@ INLINE void OPNWriteReg(int r, int v)
CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03];
/* PAN : b7 = L, b6 = R */
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? ~0 : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? ~0 : 0;
ym2612.OPN.pan[ c*2 ] = (v & 0x80) ? ~((1 << (14 - config.dac_bits)) - 1) : 0;
ym2612.OPN.pan[ c*2+1 ] = (v & 0x40) ? ~((1 << (14 - config.dac_bits)) - 1) : 0;
break;
}
break;
@ -2033,10 +2028,10 @@ unsigned int YM2612Read(void)
}
/* Generate 16 bits samples for ym2612 */
void YM2612Update(short int *buffer, int length)
void YM2612Update(long int *buffer, int length)
{
int i;
int lt,rt;
long int lt,rt;
/* refresh PG increments and EG rates if required */
refresh_fc_eg_chan(&ym2612.CH[0]);
@ -2195,4 +2190,19 @@ void YM2612Restore(unsigned char *buffer)
setup_connection(&ym2612.CH[3],3);
setup_connection(&ym2612.CH[4],4);
setup_connection(&ym2612.CH[5],5);
/* update channels mask */
unsigned int mask = ~((1 << (14 - config.dac_bits)) - 1);
ym2612.OPN.pan[0] = ym2612.OPN.pan[0] ? mask : 0;
ym2612.OPN.pan[1] = ym2612.OPN.pan[1] ? mask : 0;
ym2612.OPN.pan[2] = ym2612.OPN.pan[2] ? mask : 0;
ym2612.OPN.pan[3] = ym2612.OPN.pan[3] ? mask : 0;
ym2612.OPN.pan[4] = ym2612.OPN.pan[4] ? mask : 0;
ym2612.OPN.pan[5] = ym2612.OPN.pan[5] ? mask : 0;
ym2612.OPN.pan[6] = ym2612.OPN.pan[6] ? mask : 0;
ym2612.OPN.pan[7] = ym2612.OPN.pan[7] ? mask : 0;
ym2612.OPN.pan[8] = ym2612.OPN.pan[8] ? mask : 0;
ym2612.OPN.pan[9] = ym2612.OPN.pan[9] ? mask : 0;
ym2612.OPN.pan[10] = ym2612.OPN.pan[10] ? mask : 0;
ym2612.OPN.pan[11] = ym2612.OPN.pan[11] ? mask : 0;
}

View File

@ -21,7 +21,7 @@
extern int YM2612Init(float clock, int rate);
extern int YM2612ResetChip(void);
extern void YM2612Update(short int*buffer, int length);
extern void YM2612Update(long int *buffer, int length);
extern void YM2612Write(unsigned int a, unsigned int v);
extern unsigned int YM2612Read(void);
extern unsigned char *YM2612GetContextPtr(void);

View File

@ -25,8 +25,6 @@
#include "Fir_Resampler.h"
#include "eq.h"
#define SND_SIZE (snd.buffer_size * sizeof(int16))
/* Global variables */
t_bitmap bitmap;
t_snd snd;
@ -50,15 +48,15 @@ void audio_set_equalizer(void)
}
/****************************************************************
* AUDIO stream update
* AUDIO stream update & mixing
****************************************************************/
static int llp,rrp;
static int32 llp,rrp;
int audio_update (void)
{
int i, l, r;
int ll = llp;
int rr = rrp;
int32 i, l, r;
int32 ll = llp;
int32 rr = rrp;
int psg_preamp = config.psg_preamp;
int fm_preamp = config.fm_preamp;
@ -66,7 +64,7 @@ int audio_update (void)
uint32 factora = (config.lp_range << 16) / 100;
uint32 factorb = 0x10000 - factora;
int16 *fm = snd.fm.buffer;
int32 *fm = snd.fm.buffer;
int16 *psg = snd.psg.buffer;
#ifdef NGC
@ -109,11 +107,11 @@ int audio_update (void)
for (i = 0; i < size; i ++)
{
/* PSG samples (mono) */
l = r = ((*psg++) * psg_preamp)/100;
l = r = (((*psg++) * psg_preamp) / 100);
/* FM samples (stereo) */
l += (*fm++ * fm_preamp)/100;
r += (*fm++ * fm_preamp)/100;
l += ((*fm++ * fm_preamp) / 100);
r += ((*fm++ * fm_preamp) / 100);
/* filtering */
if (filter & 1)
@ -131,27 +129,31 @@ int audio_update (void)
r = do_3band(&eq,r);
}
/* clipping */
if (l > 32767) l = 32767;
else if (l < -32768) l = -32768;
if (r > 32767) r = 32767;
else if (r < -32768) r = -32768;
/* clipping (16-bit samples) */
if (l > 32767)
l = 32767;
else if (l < -32768)
l = -32768;
if (r > 32767)
r = 32767;
else if (r < -32768)
r = -32768;
/* update sound buffer */
#ifndef NGC
snd.buffer[0][i] = l;
snd.buffer[1][i] = r;
snd.buffer[0][i] = r;
snd.buffer[1][i] = l;
#else
*sb++ = r;
*sb++ = l;
#endif
}
/* save delayed samples for next frame */
/* save filtered samples for next frame */
llp = ll;
rrp = rr;
/* save remaining samples for next frame */
/* keep remaining samples for next frame */
memcpy(snd.fm.buffer, fm, (snd.fm.pos - snd.fm.buffer) << 1);
memcpy(snd.psg.buffer, psg, (snd.psg.pos - snd.psg.buffer) << 1);
@ -182,19 +184,19 @@ int audio_init (int samplerate, float framerate)
#ifndef NGC
/* Output buffers */
snd.buffer[0] = (int16 *) malloc(SND_SIZE);
snd.buffer[1] = (int16 *) malloc(SND_SIZE);
snd.buffer[0] = (int16 *) malloc(snd.buffer_size * sizeof(int16));
snd.buffer[1] = (int16 *) malloc(snd.buffer_size * sizeof(int16));
if (!snd.buffer[0] || !snd.buffer[1])
return (-1);
#endif
/* SN76489 stream buffers */
snd.psg.buffer = (int16 *) malloc(SND_SIZE);
snd.psg.buffer = (int16 *) malloc(snd.buffer_size * sizeof(int16));
if (!snd.psg.buffer)
return (-1);
/* YM2612 stream buffers */
snd.fm.buffer = (int16 *) malloc(SND_SIZE * 2);
snd.fm.buffer = (int32 *) malloc(snd.buffer_size * sizeof(int32) * 2);
if (!snd.fm.buffer)
return (-1);
@ -232,14 +234,14 @@ void audio_reset(void)
snd.fm.pos = snd.fm.buffer;
#ifndef NGC
if (snd.buffer[0])
memset (snd.buffer[0], 0, SND_SIZE);
memset (snd.buffer[0], 0, snd.buffer_size * sizeof(int16));
if (snd.buffer[1])
memset (snd.buffer[1], 0, SND_SIZE);
memset (snd.buffer[1], 0, snd.buffer_size * sizeof(int16));
#endif
if (snd.psg.buffer)
memset (snd.psg.buffer, 0, SND_SIZE);
memset (snd.psg.buffer, 0, snd.buffer_size * sizeof(int16));
if (snd.fm.buffer)
memset (snd.fm.buffer, 0, SND_SIZE * 2);
memset (snd.fm.buffer, 0, snd.buffer_size * sizeof(int32) * 2);
}
/****************************************************************
@ -339,8 +341,11 @@ int system_frame (int do_skip)
}
odd_frame ^= 1;
/* clear VBLANK and DMA flags */
status &= 0xFFE5;
/* clear VBLANK, DMA, FIFO FULL & field flags */
status &= 0xFEE5;
/* set FIFO EMPTY flag */
status |= 0x0200;
/* even/odd field flag (interlaced modes only) */
if (odd_frame && interlaced)
@ -382,19 +387,34 @@ int system_frame (int do_skip)
if (dma_length)
vdp_update_dma();
/* vertical blanking */
if (status & 8)
{
/* render overscan */
if (!do_skip && ((line < end_line) || (line >= start_line)))
render_line(line, 1);
/* clear any pending Z80 interrupt */
if (zirq)
{
zirq = 0;
z80_set_irq_line(0, CLEAR_LINE);
}
}
/* active display */
if (line <= vdp_height)
else
{
/* H Interrupt */
if(--h_counter < 0)
{
h_counter = reg[10];
hint_pending = 1;
hint_pending = 0x10;
if (reg[0] & 0x10)
irq_status = (irq_status & ~0x40) | 0x14;
}
/* vertical retrace */
/* end of active display */
if (line == vdp_height)
{
/* render overscan */
@ -423,32 +443,20 @@ int system_frame (int do_skip)
mcycles_z80 = mcycles_vdp + 788;
/* V Interrupt */
vint_pending = 1;
vint_pending = 0x20;
if (reg[1] & 0x20)
irq_status = (irq_status & ~0x40) | 0x36;
}
else if (!do_skip)
{
/* sprites are processed during horizontal blanking */
if (reg[1] & 0x40)
parse_satb(0x80 + line);
/* render scanline */
render_line(line, 0);
}
}
else
{
/* render overscan */
if (!do_skip && ((line < end_line) || (line >= start_line)))
render_line(line, 1);
/* clear any pending Z80 interrupt */
if (zirq)
{
zirq = 0;
z80_set_irq_line(0, CLEAR_LINE);
}
}
/* process line */
m68k_run(mcycles_vdp + MCYCLES_PER_LINE);

View File

@ -61,8 +61,8 @@ typedef struct
int16 *buffer[2]; /* Signed 16-bit stereo sound data */
struct
{
int16 *pos;
int16 *buffer;
int32 *pos;
int32 *buffer;
} fm;
struct
{

View File

@ -58,7 +58,7 @@ uint16 ntbb; /* Name table B base address */
uint16 ntwb; /* Name table W base address */
uint16 satb; /* Sprite attribute table base address */
uint16 hscb; /* Horizontal scroll table base address */
uint8 border; /* Border color index */
uint8 bg_name_dirty[0x800]; /* 1= This pattern is dirty */
uint16 bg_name_list[0x800]; /* List of modified pattern indices */
uint16 bg_list_index; /* # of modified patterns in list */
@ -66,7 +66,6 @@ uint8 bg_pattern_cache[0x80000]; /* Cached and flipped patterns */
uint8 playfield_shift; /* Width of planes A, B (in bits) */
uint8 playfield_col_mask; /* Vertical scroll mask */
uint16 playfield_row_mask; /* Horizontal scroll mask */
uint32 y_mask; /* Name table Y-index bits mask */
uint16 hc_latch; /* latched HCounter (INT2) */
uint16 v_counter; /* VDP scanline counter */
uint32 dma_length; /* Current DMA remaining bytes */
@ -84,6 +83,7 @@ static const uint8 shift_table[] = { 6, 7, 0, 8 }; /* fixes Window Bug test
static const uint8 col_mask_table[] = { 0x0F, 0x1F, 0x0F, 0x3F };
static const uint16 row_mask_table[] = { 0x0FF, 0x1FF, 0x2FF, 0x3FF };
static uint8 border; /* Border color index */
static uint16 sat_base_mask; /* Base bits of SAT */
static uint16 sat_addr_mask; /* Index bits of SAT */
static uint32 dma_endCycles; /* 68k cycles to DMA end */
@ -158,9 +158,23 @@ void vdp_reset(void)
addr_latch = 0;
code = 0;
pending = 0;
hint_pending = 0;
vint_pending = 0;
irq_status = 0;
hc_latch = 0;
v_counter = 0;
dmafill = 0;
dma_length = 0;
dma_endCycles = 0;
dma_type = 0;
odd_frame = 0;
im2_flag = 0;
interlaced = 0;
fifo_write_cnt = 0;
fifo_lastwrite = 0;
fifo_latency = 192; /* default FIFO timings */
status = 0x200; /* fifo empty */
status |= vdp_pal; /* PAL/NTSC flag */
status = vdp_pal | 0x0200; /* FIFO empty */
ntab = 0;
ntbb = 0;
@ -170,59 +184,46 @@ void vdp_reset(void)
sat_base_mask = 0xFE00;
sat_addr_mask = 0x01FF;
playfield_shift = 6;
playfield_col_mask = 0x0F;
playfield_row_mask = 0x0FF;
border = 0x00;
bg_list_index = 0;
memset ((char *) bg_name_dirty, 0, sizeof (bg_name_dirty));
memset ((char *) bg_name_list, 0, sizeof (bg_name_list));
bg_list_index = 0;
memset ((char *) bg_pattern_cache, 0, sizeof (bg_pattern_cache));
playfield_shift = 6;
playfield_col_mask = 0x0F;
playfield_row_mask = 0x0FF;
hint_pending = 0;
vint_pending = 0;
irq_status = 0;
hc_latch = 0;
v_counter = 0;
dmafill = 0;
dma_length = 0;
dma_endCycles = 0;
im2_flag = 0;
interlaced = 0;
odd_frame = 0;
fifo_write_cnt = 0;
/* reset HVC tables */
vctab = (vdp_pal) ? vc_pal_224 : vc_ntsc_224;
vctab = vdp_pal ? vc_pal_224 : vc_ntsc_224;
hctab = cycle2hc32;
/* reset display area */
bitmap.viewport.w = 256;
bitmap.viewport.h = 224;
/* reset border area */
bitmap.viewport.x = config.overscan ? ((reg[12] & 1) ? 16 : 12) : 0;
bitmap.viewport.y = config.overscan ? (vdp_pal ? 32 : 8) : 0;
bitmap.viewport.changed = 1;
/* reset overscan area */
bitmap.viewport.x = 0;
bitmap.viewport.y = 0;
if (config.overscan)
{
bitmap.viewport.x = 12;
bitmap.viewport.y = vdp_pal ? 32 : 8;
}
/* initialize some registers (normally set by BIOS) */
if (config.bios_enabled != 3)
{
reg_w(0 , 0x04); /* Palette bit set */
reg_w(1 , 0x04); /* Mode 5 enabled */
reg_w(10, 0xff); /* HINT disabled */
reg_w(12, 0x81); /* H40 mode */
reg_w(15, 0x02); /* auto increment */
}
/* default FIFO timing */
fifo_latency = 192;
}
void vdp_shutdown(void)
@ -262,36 +263,38 @@ void vdp_restore(uint8 *vdp_regs)
/* reinitialize palette */
color_update(0x00, *(uint16 *)&cram[border << 1]);
for(i = 1; i < 0x40; i += 1)
{
color_update(i, *(uint16 *)&cram[i << 1]);
}
}
/*--------------------------------------------------------------------------*/
/* DMA Timings update */
/* DMA update */
/*--------------------------------------------------------------------------*/
void vdp_update_dma()
{
int dma_cycles = 0;
uint32 dma_cycles = 0;
/* DMA timings table index */
int index = (4 * dma_type) + ((reg[12] & 1)*2);
if ((status&8) || !(reg[1] & 0x40)) index++;
/* update DMA timings */
uint32 index = dma_type;
if ((status & 8) || !(reg[1] & 0x40))
++index;
if (reg[12] & 1)
index+=2;
/* DMA transfer rate (bytes per line) */
int rate = dma_rates[index];
uint32 rate = dma_rates[index];
/* 68k cycles left */
int left_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - mcycles_68k;
if (left_cycles < 0) left_cycles = 0;
int32 left_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - mcycles_68k;
if (left_cycles < 0)
left_cycles = 0;
/* DMA bytes left */
int dma_bytes = (left_cycles * rate) / MCYCLES_PER_LINE;
uint32 dma_bytes = (left_cycles * rate) / MCYCLES_PER_LINE;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] DMA type %d (%d access/line)-> %d access (%d remaining) (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE,dma_type, rate, dma_length, dma_bytes, m68k_get_reg (NULL, M68K_REG_PC));
error("[%d(%d)][%d(%d)] DMA type %d (%d access/line)-> %d access (%d remaining) (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE,dma_type/4, rate, dma_length, dma_bytes, m68k_get_reg (NULL, M68K_REG_PC));
#endif
/* determinate DMA length in CPU cycles */
@ -309,9 +312,9 @@ void vdp_update_dma()
}
/* update 68k cycles counter */
if (dma_type < 2)
if (dma_type < 8)
{
/* 68K COPY to V-RAM */
/* 68K to VRAM, CRAM, VSRAM */
/* 68K is frozen during DMA operation */
mcycles_68k += dma_cycles;
@ -344,13 +347,11 @@ void vdp_ctrl_w(unsigned int data)
if ((data & 0xC000) == 0x8000)
{
/* VDP register write */
uint8 r = (data >> 8) & 0x1F;
uint8 d = data & 0xFF;
reg_w(r,d);
reg_w((data >> 8) & 0x1F,data & 0xFF);
}
else pending = 1;
addr = ((addr_latch & 0xC000) | (data & 0x3FFF));
addr = addr_latch | (data & 0x3FFF);
code = ((code & 0x3C) | ((data >> 14) & 0x03));
}
else
@ -358,30 +359,29 @@ void vdp_ctrl_w(unsigned int data)
/* Clear pending flag */
pending = 0;
/* Update address and code registers */
addr = ((addr & 0x3FFF) | ((data & 3) << 14));
code = ((code & 0x03) | ((data >> 2) & 0x3C));
/* Save address bits A15 and A14 */
addr_latch = (addr & 0xC000);
addr_latch = (data & 3) << 14;
/* Update address and code registers */
addr = addr_latch | (addr & 0x3FFF);
code = ((code & 0x03) | ((data >> 2) & 0x3C));
/* DMA operation */
if ((code & 0x20) && (reg[1] & 0x10))
{
switch (reg[23] & 0xC0)
switch (reg[23] >> 6)
{
case 0x00: /* V bus to VDP DMA */
case 0x40: /* V bus to VDP DMA */
dma_vbus();
break;
case 0x80: /* VRAM fill */
case 2: /* VRAM fill */
dmafill = 1;
break;
case 0xC0: /* VRAM copy */
case 3: /* VRAM copy */
dma_copy();
break;
default: /* V bus to VDP DMA */
dma_vbus();
break;
}
}
}
@ -415,36 +415,30 @@ void vdp_ctrl_w(unsigned int data)
* 1 DMA Busy
* 2 During HBlank
* 3 During VBlank
* 4 Frame Interlace 0:even 1:odd
* 4 0:1 even:odd field (interlaced modes)
* 5 Sprite collision
* 6 Too many sprites per line
* 7 v interrupt occurred
* 8 Write FIFO full
* 9 Write FIFO empty
* 10 - 15 Next word on bus
* 10 - 15 Open Bus
*/
unsigned int vdp_ctrl_r(void)
{
/* update FIFO flags */
fifo_update();
if (fifo_write_cnt < 4)
{
status &= 0xFEFF;
if (fifo_write_cnt == 0) status |= 0x200;
}
else status ^= 0x200;
/* update DMA Busy flag */
if ((status & 2) && !dma_length && (mcycles_68k >= dma_endCycles))
status &= 0xFFFD;
unsigned int temp = status;
uint32 temp = status;
/* display OFF: VBLANK flag is set */
if (!(reg[1] & 0x40))
temp |= 0x08;
/* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican) */
/* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican, Gouketsuji Ichizoku) */
if ((mcycles_68k % MCYCLES_PER_LINE) < 588)
temp |= 0x04;
@ -466,7 +460,8 @@ unsigned int vdp_hvc_r(void)
uint8 vc = vctab[v_counter];
/* interlace mode 2 */
if (im2_flag) vc = (vc << 1) | ((vc >> 7) & 1);
if (im2_flag)
vc = (vc << 1) | ((vc >> 7) & 1);
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VDP HVC Read -> 0x%04x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE,(vc << 8) | hc, m68k_get_reg (NULL, M68K_REG_PC));
@ -492,10 +487,12 @@ void vdp_data_w(unsigned int data)
return;
}
/* update VDP FIFO (during HDISPLAY only) */
/* restricted VDP writes during active display */
if (!(status&8) && (reg[1]&0x40))
{
/* update VDP FIFO */
fifo_update();
if (fifo_write_cnt == 0)
{
/* reset cycle counter */
@ -508,12 +505,13 @@ void vdp_data_w(unsigned int data)
/* increase FIFO word count */
fifo_write_cnt ++;
/* is FIFO full ? */
/* FIFO full ? */
if (fifo_write_cnt >= 4)
{
/* update VDP status flag */
status |= 0x100;
/* VDP latency (Chaos Engine, Soldiers of Fortune, Double Clutch) */
/* CPU is delayed (Chaos Engine, Soldiers of Fortune, Double Clutch) */
if (fifo_write_cnt > 4)
mcycles_68k = fifo_lastwrite + fifo_latency;
}
@ -580,6 +578,16 @@ int vdp_int_ack_callback(int int_level)
#ifdef LOGVDP
error("---> VINT cleared\n");
#endif
/* update IRQ status */
if (hint_pending & reg[0])
{
irq_status = 0x14;
}
else
{
irq_status = 0x00;
m68k_set_irq(0);
}
}
else
{
@ -587,16 +595,17 @@ int vdp_int_ack_callback(int int_level)
#ifdef LOGVDP
error("---> HINT cleared\n");
#endif
}
/* update IRQ status */
irq_status = 0;
if (vint_pending && (reg[1] & 0x20))
irq_status |= 0x16;
else if (hint_pending && (reg[0] & 0x10))
irq_status |= 0x14;
if (vint_pending & reg[1])
{
irq_status = 0x16;
}
else
{
irq_status = 0x00;
m68k_set_irq(0);
}
}
return M68K_INT_ACK_AUTOVECTOR;
}
@ -613,8 +622,20 @@ static inline void fifo_update()
if (fifo_read > 0)
{
fifo_write_cnt -= fifo_read;
if (fifo_write_cnt < 0)
/* update VDP status flags */
if (fifo_write_cnt < 4)
{
/* FIFO is not full anymore */
status &= 0xFEFF;
if (fifo_write_cnt <= 0)
{
/* FIFO is empty */
status |= 0x200;
fifo_write_cnt = 0;
}
}
/* update cycle count */
fifo_lastwrite += (fifo_read * fifo_latency);
@ -636,7 +657,8 @@ static inline void data_w(unsigned int data)
#endif
/* Byte-swap data if A0 is set */
if (addr & 1) data = (data >> 8) | (data << 8);
if (addr & 1)
data = ((data >> 8) | (data << 8)) & 0xFFFF;
/* Copy SAT data to the internal SAT */
if ((addr & sat_base_mask) == satb)
@ -705,10 +727,6 @@ static inline void data_w(unsigned int data)
addr += reg[15];
}
/*
The reg[] array is updated at the *end* of this function, so the new
register data can be compared with the previous data.
*/
static inline void reg_w(unsigned int r, unsigned int d)
{
#ifdef LOGVDP
@ -726,79 +744,95 @@ static inline void reg_w(unsigned int r, unsigned int d)
{
case 0: /* CTRL #1 */
/* look for changed bits */
r = d ^ reg[r];
reg[0] = d;
/* Line Interrupt */
if (((d&0x10) != (reg[0]&0x10)) && hint_pending)
if ((r & 0x10) && hint_pending)
{
/* update IRQ status */
irq_status = 0x50;
if (vint_pending && (reg[1] & 0x20))
if (vint_pending & reg[1])
irq_status |= 0x26;
else if (d & 0x10)
irq_status |= 4;
}
/* Palette bit */
if ((d&0x04) != (reg[0]&0x04))
if (r & 0x04)
{
/* Update colors */
reg[0] = d;
int i;
color_update (0x00, *(uint16 *) & cram[border << 1]);
for (i = 1; i < 0x40; i += 1)
{
color_update (i, *(uint16 *) & cram[i << 1]);
}
}
break;
case 1: /* CTRL #2 */
/* look for changed bits */
r = d ^ reg[r];
reg[1] = d;
/* Frame Interrupt */
if (((d&0x20) != (reg[1]&0x20)) && vint_pending)
if ((r & 0x20) && vint_pending)
{
/* update IRQ status */
irq_status = 0x50;
if (d & 0x20)
irq_status |= 0x26;
else if (hint_pending && (reg[0] & 0x10))
else if (hint_pending & reg[0])
irq_status |= 4;
}
/* See if the viewport height has actually been changed */
if ((d & 8) != (reg[1] & 8))
if (r & 0x08)
{
/* PAL mode only ! */
if (vdp_pal)
{
if (d & 8)
{
bitmap.viewport.h = 240;
if (config.overscan)
bitmap.viewport.y = 24;
vctab = vc_pal_240;
}
else
{
bitmap.viewport.h = 224;
if (config.overscan)
bitmap.viewport.y = 32;
vctab = vc_pal_224;
}
/* update viewport */
bitmap.viewport.changed = 1;
bitmap.viewport.h = (d & 8) ? 240 : 224;
if (config.overscan) bitmap.viewport.y = ((vdp_pal ? 288 : 240) - bitmap.viewport.h) / 2;
/* update VC table */
if (vdp_pal)
vctab = (d & 8) ? vc_pal_240 : vc_pal_224;
}
}
/* Display status modified during Horizontal Blanking (Legend of Galahad, Lemmings 2, */
/* Nigel Mansell's World Championship Racing, Deadly Moves, Power Athlete). */
/* Nigel Mansell's World Championship Racing, Deadly Moves, Power Athlete, ...) */
/* */
/* Note that this is not entirely correct since we are cheating with the HBLANK period limits */
/* and still redrawing the whole line. This is done because some game (PAL version of Nigel */
/* Mansell's World Championship Racing actually) appear to disable display outside HBLANK. On */
/* real hardware, the raster line would appear partially blanked. */
if (((d&0x40) != (reg[1]&0x40)) && !(status & 8))
if ((r & 0x40) && !(status & 8))
{
if (mcycles_68k <= (hint_68k + 860))
{
reg[1] = d;
#ifdef LOGVDP
error("Line redrawn (%d sprites) \n",object_index_count);
#endif
/* If display was disabled during HBLANK (Mickey Mania 3D level), sprite processing is limited */
/* Below values have been deducted from testing on this game, accurate emulation would require */
/* to know exact sprite (pre)processing timings. Hopefully, they don't seem to break any other */
/* games, so they might not be so much inaccurate. */
if ((d&0x40) && (mcycles_68k % MCYCLES_PER_LINE >= 360) && (object_index_count > 5))
if ((d&0x40) && (object_index_count > 5) && (mcycles_68k % MCYCLES_PER_LINE >= 360))
object_index_count = 5;
#ifdef LOGVDP
error("Line redrawn (%d sprites) \n",object_index_count);
#endif
/* re-render line */
render_line(v_counter, 0);
}
@ -810,46 +844,46 @@ static inline void reg_w(unsigned int r, unsigned int d)
break;
case 2: /* NTAB */
reg[2] = d;
ntab = (d << 10) & 0xE000;
break;
case 3: /* NTWB */
reg[3] = d;
if (reg[12] & 1)
ntwb = (d << 10) & 0xF000;
else
ntwb = (d << 10) & 0xF800;
if(reg[12] & 1) ntwb &= 0xF000;
break;
case 4: /* NTBB */
reg[4] = d;
ntbb = (d << 13) & 0xE000;
break;
case 5: /* SATB */
reg[5] = d;
if (reg[12] & 1)
{
sat_base_mask = 0xFC00;
sat_addr_mask = 0x03FF;
}
satb = (d << 9) & 0xFC00;
else
{
sat_base_mask = 0xFE00;
sat_addr_mask = 0x01FF;
}
satb = (d << 9) & sat_base_mask;
satb = (d << 9) & 0xFE00;
break;
case 7:
/* See if the border color has actually changed */
reg[7] = d;
/* See if the background color has actually changed */
d &= 0x3F;
if (d != border)
{
/* Mark the border color as modified */
/* update background color */
border = d;
color_update(0x00, *(uint16 *)&cram[(border << 1)]);
color_update(0x00, *(uint16 *)&cram[(d << 1)]);
/* Background color modified during Horizontal Blanking (Road Rash 1,2,3)*/
/* background color modified during Horizontal Blanking (Road Rash 1,2,3)*/
if (!(status & 8) && (mcycles_68k <= (mcycles_vdp + 860)))
{
/* remap colors */
reg[7] = d;
remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x);
#ifdef LOGVDP
error("--> Line remapped\n");
@ -863,38 +897,51 @@ static inline void reg_w(unsigned int r, unsigned int d)
break;
case 12:
/* look for changed bits */
r = d ^ reg[r];
reg[12] = d;
/* See if the viewport width has actually been changed */
if ((d & 1) != (reg[12] & 1))
if (r & 0x01)
{
if (d & 1)
{
/* Update display-dependant registers */
ntwb = (reg[3] << 10) & 0xF000;
satb = (reg[5] << 9) & 0xFC00;
sat_base_mask = 0xFC00;
sat_addr_mask = 0x03FF;
satb = (reg[5] << 9) & sat_base_mask;
/* Update HC table */
hctab = cycle2hc40;
/* Update viewport width */
bitmap.viewport.w = 320;
if (config.overscan) bitmap.viewport.x = 16;
if (config.overscan)
bitmap.viewport.x = 16;
/* Update fifo timings */
fifo_latency = ((code & 0x0F) == 0x01) ? 384 : 192;
}
else
{
/* Update display-dependant registers */
ntwb = (reg[3] << 10) & 0xF800;
satb = (reg[5] << 9) & 0xFE00;
sat_base_mask = 0xFE00;
sat_addr_mask = 0x01FF;
satb = (reg[5] << 9) & sat_base_mask;
/* Update HC table */
hctab = cycle2hc32;
/* Update viewport width */
bitmap.viewport.w = 256;
if (config.overscan) bitmap.viewport.x = 12;
if (config.overscan)
bitmap.viewport.x = 12;
/* Update fifo timings */
fifo_latency = ((code & 0x0F) == 0x01) ? 420 : 210;
}
/* Update viewport */
@ -905,27 +952,23 @@ static inline void reg_w(unsigned int r, unsigned int d)
}
/* See if the S/TE mode bit has changed */
if ((d & 8) != (reg[12] & 8))
if (r & 0x08)
{
int i;
/* The following color update check this value */
reg[12] = d;
/* Update colors */
int i;
color_update (0x00, *(uint16 *) & cram[border << 1]);
for (i = 1; i < 0x40; i += 1)
{
color_update (i, *(uint16 *) & cram[i << 1]);
}
}
break;
case 13: /* HScroll Base Address */
reg[13] = d;
hscb = (d << 10) & 0xFC00;
break;
case 16: /* Playfield size */
reg[16] = d;
playfield_shift = shift_table[(d & 3)];
playfield_col_mask = col_mask_table[(d & 3)];
playfield_row_mask = row_mask_table[(d >> 4) & 3];
@ -935,10 +978,11 @@ static inline void reg_w(unsigned int r, unsigned int d)
reg[17] = d;
window_clip();
break;
}
/* Write new register value */
default:
reg[r] = d;
break;
}
}
/*--------------------------------------------------------------------------*/
@ -955,11 +999,13 @@ static inline void reg_w(unsigned int r, unsigned int d)
static inline void dma_copy(void)
{
int name;
int length = (reg[20] << 8 | reg[19]) & 0xFFFF;
int source = (reg[22] << 8 | reg[21]) & 0xFFFF;
if (!length) length = 0x10000;
uint32 length = (reg[20] << 8 | reg[19]) & 0xFFFF;
uint32 source = (reg[22] << 8 | reg[21]) & 0xFFFF;
dma_type = 3;
if (!length)
length = 0x10000;
dma_type = 12;
dma_length = length;
vdp_update_dma();
@ -982,15 +1028,16 @@ static inline void dma_copy(void)
/* 68K Copy to VRAM, VSRAM or CRAM */
static inline void dma_vbus (void)
{
uint32 base, source = ((reg[23] & 0x7F) << 17 | reg[22] << 9 | reg[21] << 1) & 0xFFFFFE;
uint32 source = ((reg[23] & 0x7F) << 17 | reg[22] << 9 | reg[21] << 1) & 0xFFFFFE;
uint32 base = source;
uint32 length = (reg[20] << 8 | reg[19]) & 0xFFFF;
uint32 temp;
if (!length) length = 0x10000;
base = source;
if (!length)
length = 0x10000;
/* DMA timings */
dma_type = (code & 0x06) ? 1 : 0;
dma_type = (code & 0x06) ? 4 : 0;
dma_length = length;
vdp_update_dma();
@ -1055,11 +1102,13 @@ static inline void dma_vbus (void)
static inline void dma_fill(unsigned int data)
{
int name;
int length = (reg[20] << 8 | reg[19]) & 0xFFFF;
if (!length) length = 0x10000;
uint32 length = (reg[20] << 8 | reg[19]) & 0xFFFF;
if (!length)
length = 0x10000;
/* DMA timings */
dma_type = 2;
dma_type = 8;
dma_length = length;
vdp_update_dma();

View File

@ -46,7 +46,7 @@ extern uint16 ntbb;
extern uint16 ntwb;
extern uint16 satb;
extern uint16 hscb;
extern uint8 border;
extern uint8 bg_name_dirty[0x800];
extern uint16 bg_name_list[0x800];
extern uint16 bg_list_index;