Problems / limitations\r
----------------------\r
\r
-* 32x and SVP are not emulated.\r
+* 32x is not emulated.\r
+#ifdef PSP\r
+* SVP is not emulated.\r
+#endif\r
* Various VDP quirks (window bug, scroll size 2, etc.) are not emulated,\r
as very few games use this (if any at all).\r
-* Some games don't work or have glitches because of inaccurate timing and sync\r
- between the emulated chips.\r
+* The emulator is not 100% accurate, so some things may not work as expected.\r
\r
\r
Credits\r
* Charles MacDonald (http://cgfm2.emuviews.com/) for old but still very useful\r
info about genesis hardware.\r
* Steve Snake for all that he has done for Genesis emulation scene.\r
+* Tasco Deluxe for his reverse engineering work on SVP and some mappers.\r
* Bart Trzynadlowski for his SSFII and 68000 docs.\r
* Haze for his research (http://haze.mameworld.info).\r
* Mark and Jean-loup for zlib library.\r
\r
Changelog\r
---------\r
+1.40\r
+ + Added support for SVP (Sega Virtua Processor) to emulate Virtua Racing,\r
+ wrote ARM recompiler and some HLE code for VR.\r
+ * Changed config file format, files are now human-readable. Game specific\r
+ configs are now held in single file (but old game config files are still\r
+ read).\r
+ * Fixed a bug where some key combos didn't work.\r
+\r
1.35b\r
* PSP: mp3 code should no longer fail on 1.5 firmware.\r
+ PSP: added gamma adjustment option.\r
#define NL "\n"
-static void mystrip(char *str)
+static char *mystrip(char *str)
{
int i, len;
for (i = 0; i < len; i++)
if (str[i] != ' ') break;
if (i > 0) memmove(str, str + i, len - i + 1);
+
len = strlen(str);
for (i = len - 1; i >= 0; i--)
if (str[i] != ' ') break;
str[i+1] = 0;
+
+ return str;
}
#endif
for (i = 0; i < sizeof(me_ctrl_actions) / sizeof(me_ctrl_actions[0]); i++) {
if (me_ctrl_actions[i].mask & binds[t]) {
- sprintf(act, "player%i ", ((binds[t]>>16)&1)+1);
- strncpy(act + 8, me_ctrl_actions[i].name, 31);
- break;
+ strncpy(act, me_ctrl_actions[i].name, 31);
+ fprintf(fn, "%s %s = player%i %s" NL, bind_str, names[t],
+ ((binds[t]>>16)&1)+1, mystrip(act));
}
}
- if (act[0] == 0)
- {
- for (i = 0; emuctrl_actions[i].name != NULL; i++)
- if (emuctrl_actions[i].mask & binds[t]) {
- strncpy(act, emuctrl_actions[i].name, 31);
- break;
- }
- }
- mystrip(act);
- fprintf(fn, "%s %s = %s" NL, bind_str, names[t], act);
+ for (i = 0; emuctrl_actions[i].name != NULL; i++) {
+ if (emuctrl_actions[i].mask & binds[t]) {
+ strncpy(act, emuctrl_actions[i].name, 31);
+ fprintf(fn, "%s %s = %s" NL, bind_str, names[t], mystrip(act));
+ }
+ }
}
}
}
+static unsigned int keys_encountered = 0;
+
static void keys_parse(const char *var, const char *val, int binds[32], const char *names[32])
{
- int t, i, keys_encountered = 0;
+ int t, i;
unsigned int player;
for (t = 0; t < 32; t++)
return;
}
- if (!(keys_encountered & (1<<t))) {
+ if (binds == currentConfig.KeyBinds && !(keys_encountered & (1<<t))) { // hack
binds[t] = 0;
keys_encountered |= 1<<t;
}
fail:
lprintf("unhandled action \"%s\"\n", val);
return;
-
}
}
}
+ keys_encountered = 0;
+
while (!feof(f))
{
tmp = fgets(line, sizeof(line), f);
int state_slot = 0;\r
int config_slot = 0, config_slot_current = 0;\r
char lastRomFile[512];\r
+int kb_combo_keys = 0, kb_combo_acts = 0; // keys and actions which need button combos\r
\r
unsigned char *movie_data = NULL;\r
static int movie_size = 0;\r
char *emu_makeRomId(void)\r
{\r
static char id_string[3+0x11+0x11+0x30+16];\r
- int pos;\r
+ int pos, swab = 1;\r
\r
- if (PicoMCD & 1)\r
- strcpy(id_string, "CD|");\r
+ if (PicoMCD & 1) {\r
+ strcpy(id_string, "CD|");\r
+ swab = 0;\r
+ }\r
else strcpy(id_string, "MD|");\r
pos = 3;\r
\r
- pos += extract_text(id_string + pos, id_header + 0x80, 0x0e, 1); // serial\r
+ pos += extract_text(id_string + pos, id_header + 0x80, 0x0e, swab); // serial\r
id_string[pos] = '|'; pos++;\r
- pos += extract_text(id_string + pos, id_header + 0xf0, 0x03, 1); // region\r
+ pos += extract_text(id_string + pos, id_header + 0xf0, 0x03, swab); // region\r
id_string[pos] = '|'; pos++;\r
- pos += extract_text(id_string + pos, id_header + 0x50, 0x30, 1); // overseas name\r
+ pos += extract_text(id_string + pos, id_header + 0x50, 0x30, swab); // overseas name\r
id_string[pos] = 0;\r
\r
return id_string;\r
cd_state = emu_cdCheck(&cd_region);\r
if (cd_state > 0)\r
{\r
+ PicoMCD |= 1;\r
// valid CD image, check for BIOS..\r
\r
// we need to have config loaded at this point\r
}\r
if (!emu_findBios(cd_region, &used_rom_name)) {\r
// bios_help() ?\r
+ PicoMCD &= ~1;\r
return 0;\r
}\r
\r
- PicoMCD |= 1;\r
get_ext(used_rom_name, ext);\r
}\r
else\r
}\r
}\r
\r
+void emu_findKeyBindCombos(void)\r
+{\r
+ int act, u;\r
+\r
+ // find out which keys and actions are combos\r
+ kb_combo_keys = kb_combo_acts = 0;\r
+ for (act = 0; act < 32; act++)\r
+ {\r
+ int keyc = 0, keyc2 = 0;\r
+ if (act == 16 || act == 17) continue; // player2 flag\r
+ if (act > 17)\r
+ {\r
+ for (u = 0; u < 32; u++)\r
+ if (currentConfig.KeyBinds[u] & (1 << act)) keyc++;\r
+ }\r
+ else\r
+ {\r
+ for (u = 0; u < 32; u++)\r
+ if ((currentConfig.KeyBinds[u] & 0x30000) == 0 && // pl. 1\r
+ (currentConfig.KeyBinds[u] & (1 << act))) keyc++;\r
+ for (u = 0; u < 32; u++)\r
+ if ((currentConfig.KeyBinds[u] & 0x30000) == 1 && // pl. 2\r
+ (currentConfig.KeyBinds[u] & (1 << act))) keyc2++;\r
+ if (keyc2 > keyc) keyc = keyc2;\r
+ }\r
+ if (keyc > 1)\r
+ {\r
+ // loop again and mark those keys and actions as combo\r
+ for (u = 0; u < 32; u++)\r
+ {\r
+ if (currentConfig.KeyBinds[u] & (1 << act)) {\r
+ kb_combo_keys |= 1 << u;\r
+ kb_combo_acts |= 1 << act;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // printf("combo keys/acts: %08x %08x\n", kb_combo_keys, kb_combo_acts);\r
+}\r
+\r
\r
void emu_updateMovie(void)\r
{\r
return ret;\r
}\r
}\r
+\r
extern int config_slot, config_slot_current;
extern unsigned char *movie_data;
extern char lastRomFile[512];
+extern int kb_combo_keys, kb_combo_acts; // keys and actions which need button combos
int emu_ReloadRom(void);
void emu_textOut8 (int x, int y, const char *text);
void emu_textOut16(int x, int y, const char *text);
char *emu_makeRomId(void);
+void emu_findKeyBindCombos(void);
extern const char *keyNames[];
void emu_prepareDefaultConfig(void);
static short __attribute__((aligned(4))) sndBuffer[2*44100/50];\r
static struct timeval noticeMsgTime = { 0, 0 }; // when started showing\r
static int osd_fps_x;\r
-static int combo_keys = 0, combo_acts = 0; // keys and actions which need button combos\r
static int gp2x_old_gamma = 100;\r
char noticeMsg[64]; // notice msg to draw\r
unsigned char *PicoDraw2FB = NULL; // temporary buffer for alt renderer\r
}\r
\r
\r
-static void find_combos(void)\r
-{\r
- int act, u;\r
-\r
- // find out which keys and actions are combos\r
- combo_keys = combo_acts = 0;\r
- for (act = 0; act < 32; act++)\r
- {\r
- int keyc = 0, keyc2 = 0;\r
- if (act == 16 || act == 17) continue; // player2 flag\r
- if (act > 17)\r
- {\r
- for (u = 0; u < 32; u++)\r
- if (currentConfig.KeyBinds[u] & (1 << act)) keyc++;\r
- }\r
- else\r
- {\r
- for (u = 0; u < 32; u++)\r
- if ((currentConfig.KeyBinds[u] & 0x30000) == 0 && // pl. 1\r
- (currentConfig.KeyBinds[u] & (1 << act))) keyc++;\r
- for (u = 0; u < 32; u++)\r
- if ((currentConfig.KeyBinds[u] & 0x30000) == 1 && // pl. 2\r
- (currentConfig.KeyBinds[u] & (1 << act))) keyc2++;\r
- if (keyc2 > keyc) keyc = keyc2;\r
- }\r
- if (keyc > 1)\r
- {\r
- // loop again and mark those keys and actions as combo\r
- for (u = 0; u < 32; u++)\r
- {\r
- if (currentConfig.KeyBinds[u] & (1 << act)) {\r
- combo_keys |= 1 << u;\r
- combo_acts |= 1 << act;\r
- }\r
- }\r
- }\r
- }\r
-\r
- // printf("combo keys/acts: %08x %08x\n", combo_keys, combo_acts);\r
-}\r
-\r
-\r
static void scaling_update(void)\r
{\r
PicoOpt &= ~0x4100;\r
\r
for (i = 0; i < 32; i++)\r
{\r
- if (keys & (1 << i)) {\r
+ if (keys & (1 << i))\r
+ {\r
int pl, acts = currentConfig.KeyBinds[i];\r
if (!acts) continue;\r
pl = (acts >> 16) & 1;\r
- if (combo_keys & (1 << i)) {\r
- int u = i+1, acts_c = acts & combo_acts;\r
+ if (kb_combo_keys & (1 << i))\r
+ {\r
+ int u, acts_c = acts & kb_combo_acts;\r
// let's try to find the other one\r
- if (acts_c)\r
- for (; u < 32; u++)\r
- if ( (currentConfig.KeyBinds[u] & acts_c) && (keys & (1 << u)) ) {\r
- allActions[pl] |= acts_c;\r
+ if (acts_c) {\r
+ for (u = i + 1; u < 32; u++)\r
+ if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) {\r
+ allActions[pl] |= acts_c & currentConfig.KeyBinds[u];\r
keys &= ~((1 << i) | (1 << u));\r
break;\r
}\r
+ }\r
// add non-combo actions if combo ones were not found\r
if (!acts_c || u == 32)\r
- allActions[pl] |= acts & ~combo_acts;\r
+ allActions[pl] |= acts & ~kb_combo_acts;\r
} else {\r
allActions[pl] |= acts;\r
}\r
scaling_update();\r
Pico.m.dirtyPal = 1;\r
oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;\r
- find_combos();\r
+ emu_findKeyBindCombos();\r
\r
// pal/ntsc might have changed, reset related stuff\r
target_fps = Pico.m.pal ? 50 : 60;\r
case 0: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 0); return;\r
case 1: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 1); return;\r
case 2: key_config_loop(emuctrl_actions,\r
- sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]), -1); return;\r
+ sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;\r
case 3: if (!rom_loaded) emu_WriteConfig(0); return;\r
default: return;\r
}\r
unsigned char *PicoDraw2FB = (unsigned char *)VRAM_CACHED_STUFF + 8; // +8 to be able to skip border with 1 quadword..
int engineState = PGS_Menu;
-static int combo_keys = 0, combo_acts = 0; // keys and actions which need button combos
static unsigned int noticeMsgTime = 0;
int reset_timing = 0; // do we need this?
int pl, acts = currentConfig.KeyBinds[i];
if (!acts) continue;
pl = (acts >> 16) & 1;
- if (combo_keys & (1 << i))
+ if (kb_combo_keys & (1 << i))
{
- int u = i+1, acts_c = acts & combo_acts;
+ int u, acts_c = acts & kb_combo_acts;
// let's try to find the other one
- if (acts_c)
- for (; u < 32; u++)
- if ( (currentConfig.KeyBinds[u] & acts_c) && (keys & (1 << u)) ) {
- allActions[pl] |= acts_c;
+ if (acts_c) {
+ for (u = i + 1; u < 32; u++)
+ if ( (keys & (1 << u)) && (currentConfig.KeyBinds[u] & acts_c) ) {
+ allActions[pl] |= acts_c & currentConfig.KeyBinds[u];
keys &= ~((1 << i) | (1 << u));
break;
}
+ }
// add non-combo actions if combo ones were not found
if (!acts_c || u == 32)
- allActions[pl] |= acts & ~combo_acts;
+ allActions[pl] |= acts & ~kb_combo_acts;
} else {
allActions[pl] |= acts;
}
prevEvents = (allActions[0] | allActions[1]) >> 16;
}
-static void find_combos(void)
-{
- int act, u;
-
- // find out which keys and actions are combos
- combo_keys = combo_acts = 0;
- for (act = 0; act < 32; act++)
- {
- int keyc = 0, keyc2 = 0;
- if (act == 16 || act == 17) continue; // player2 flag
- if (act > 17)
- {
- for (u = 0; u < 28; u++) // 28 because nub can't produce combos
- if (currentConfig.KeyBinds[u] & (1 << act)) keyc++;
- }
- else
- {
- for (u = 0; u < 28; u++)
- if ((currentConfig.KeyBinds[u] & 0x30000) == 0 && // pl. 1
- (currentConfig.KeyBinds[u] & (1 << act))) keyc++;
- for (u = 0; u < 28; u++)
- if ((currentConfig.KeyBinds[u] & 0x30000) == 1 && // pl. 2
- (currentConfig.KeyBinds[u] & (1 << act))) keyc2++;
- }
- if (keyc > 1 || keyc2 > 1)
- {
- // loop again and mark those keys and actions as combo
- for (u = 0; u < 28; u++)
- {
- if (currentConfig.KeyBinds[u] & (1 << act)) {
- combo_keys |= 1 << u;
- combo_acts |= 1 << act;
- }
- }
- }
- }
-}
-
static void simpleWait(unsigned int until)
{
clearArea(1);
Pico.m.dirtyPal = 1;
oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;
- find_combos();
+ emu_findKeyBindCombos();
// pal/ntsc might have changed, reset related stuff
target_fps = Pico.m.pal ? 50 : 60;
case 0: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 0); return;
case 1: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 1); return;
case 2: key_config_loop(emuctrl_actions,
- sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]), -1); return;
+ sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;
case 3: if (!rom_loaded) emu_WriteConfig(0); return;
default: return;
}