diff options
Diffstat (limited to 'src/emu/driver.c')
-rw-r--r-- | src/emu/driver.c | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/src/emu/driver.c b/src/emu/driver.c new file mode 100644 index 00000000000..d527ed766b9 --- /dev/null +++ b/src/emu/driver.c @@ -0,0 +1,520 @@ +/*************************************************************************** + + driver.c + + Driver construction helpers. + + Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "driver.h" +#include <ctype.h> + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define DRIVER_LRU_SIZE 10 + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static int driver_lru[DRIVER_LRU_SIZE]; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static int penalty_compare(const char *source, const char *target); + + + +/*************************************************************************** + MISCELLANEOUS BITS & PIECES +***************************************************************************/ + +/*------------------------------------------------- + expand_machine_driver - construct a machine + driver from the macroized state +-------------------------------------------------*/ + +void expand_machine_driver(void (*constructor)(machine_config *), machine_config *output) +{ + /* initialize the tag on the first screen */ + memset(output, 0, sizeof(*output)); + output->watchdog_time = attotime_zero; + + /* keeping this function allows us to pre-init the driver before constructing it */ + (*constructor)(output); + + /* if no screen tagged, tag screen 0 as main */ + if (output->screen[0].tag == NULL && output->screen[0].defstate.format != BITMAP_FORMAT_INVALID) + output->screen[0].tag = "main"; + + /* if no screens, set a dummy refresh for the main screen */ + if (output->screen[0].tag == NULL) + output->screen[0].defstate.refresh = HZ_TO_ATTOSECONDS(60); +} + + +/*------------------------------------------------- + driver_add_cpu - add a CPU during machine + driver expansion +-------------------------------------------------*/ + +cpu_config *driver_add_cpu(machine_config *machine, const char *tag, cpu_type type, int cpuclock) +{ + int cpunum; + + for (cpunum = 0; cpunum < MAX_CPU; cpunum++) + if (machine->cpu[cpunum].type == CPU_DUMMY) + { + machine->cpu[cpunum].tag = tag; + machine->cpu[cpunum].type = type; + machine->cpu[cpunum].clock = cpuclock; + return &machine->cpu[cpunum]; + } + + fatalerror("Out of CPU's!\n"); + return NULL; +} + + +/*------------------------------------------------- + driver_find_cpu - find a tagged CPU during + machine driver expansion +-------------------------------------------------*/ + +cpu_config *driver_find_cpu(machine_config *machine, const char *tag) +{ + int cpunum; + + for (cpunum = 0; cpunum < MAX_CPU; cpunum++) + if (machine->cpu[cpunum].tag && strcmp(machine->cpu[cpunum].tag, tag) == 0) + return &machine->cpu[cpunum]; + + fatalerror("Can't find CPU '%s'!\n", tag); + return NULL; +} + + +/*------------------------------------------------- + driver_remove_cpu - remove a tagged CPU + during machine driver expansion +-------------------------------------------------*/ + +void driver_remove_cpu(machine_config *machine, const char *tag) +{ + int cpunum; + + for (cpunum = 0; cpunum < MAX_CPU; cpunum++) + if (machine->cpu[cpunum].tag && strcmp(machine->cpu[cpunum].tag, tag) == 0) + { + memmove(&machine->cpu[cpunum], &machine->cpu[cpunum + 1], sizeof(machine->cpu[0]) * (MAX_CPU - cpunum - 1)); + memset(&machine->cpu[MAX_CPU - 1], 0, sizeof(machine->cpu[0])); + return; + } + + fatalerror("Can't find CPU '%s'!\n", tag); +} + + +/*------------------------------------------------- + driver_add_speaker - add a speaker during + machine driver expansion +-------------------------------------------------*/ + +speaker_config *driver_add_speaker(machine_config *machine, const char *tag, float x, float y, float z) +{ + int speakernum; + + for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++) + if (machine->speaker[speakernum].tag == NULL) + { + machine->speaker[speakernum].tag = tag; + machine->speaker[speakernum].x = x; + machine->speaker[speakernum].y = y; + machine->speaker[speakernum].z = z; + return &machine->speaker[speakernum]; + } + + fatalerror("Out of speakers!\n"); + return NULL; +} + + +/*------------------------------------------------- + driver_find_speaker - find a tagged speaker + system during machine driver expansion +-------------------------------------------------*/ + +speaker_config *driver_find_speaker(machine_config *machine, const char *tag) +{ + int speakernum; + + for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++) + if (machine->speaker[speakernum].tag && strcmp(machine->speaker[speakernum].tag, tag) == 0) + return &machine->speaker[speakernum]; + + fatalerror("Can't find speaker '%s'!\n", tag); + return NULL; +} + + +/*------------------------------------------------- + driver_remove_speaker - remove a tagged speaker + system during machine driver expansion +-------------------------------------------------*/ + +void driver_remove_speaker(machine_config *machine, const char *tag) +{ + int speakernum; + + for (speakernum = 0; speakernum < MAX_SPEAKER; speakernum++) + if (machine->speaker[speakernum].tag && strcmp(machine->speaker[speakernum].tag, tag) == 0) + { + memmove(&machine->speaker[speakernum], &machine->speaker[speakernum + 1], sizeof(machine->speaker[0]) * (MAX_SPEAKER - speakernum - 1)); + memset(&machine->speaker[MAX_SPEAKER - 1], 0, sizeof(machine->speaker[0])); + return; + } + + fatalerror("Can't find speaker '%s'!\n", tag); +} + + +/*------------------------------------------------- + driver_add_sound - add a sound system during + machine driver expansion +-------------------------------------------------*/ + +sound_config *driver_add_sound(machine_config *machine, const char *tag, sound_type type, int clock) +{ + int soundnum; + + for (soundnum = 0; soundnum < MAX_SOUND; soundnum++) + if (machine->sound[soundnum].type == SOUND_DUMMY) + { + machine->sound[soundnum].tag = tag; + machine->sound[soundnum].type = type; + machine->sound[soundnum].clock = clock; + machine->sound[soundnum].config = NULL; + machine->sound[soundnum].routes = 0; + return &machine->sound[soundnum]; + } + + fatalerror("Out of sounds!\n"); + return NULL; +} + + +/*------------------------------------------------- + driver_find_sound - find a tagged sound + system during machine driver expansion +-------------------------------------------------*/ + +sound_config *driver_find_sound(machine_config *machine, const char *tag) +{ + int soundnum; + + for (soundnum = 0; soundnum < MAX_SOUND; soundnum++) + if (machine->sound[soundnum].tag && strcmp(machine->sound[soundnum].tag, tag) == 0) + return &machine->sound[soundnum]; + + fatalerror("Can't find sound '%s'!\n", tag); + return NULL; +} + + +/*------------------------------------------------- + driver_remove_sound - remove a tagged sound + system during machine driver expansion +-------------------------------------------------*/ + +void driver_remove_sound(machine_config *machine, const char *tag) +{ + int soundnum; + + for (soundnum = 0; soundnum < MAX_SOUND; soundnum++) + if (machine->sound[soundnum].tag && strcmp(machine->sound[soundnum].tag, tag) == 0) + { + memmove(&machine->sound[soundnum], &machine->sound[soundnum + 1], sizeof(machine->sound[0]) * (MAX_SOUND - soundnum - 1)); + memset(&machine->sound[MAX_SOUND - 1], 0, sizeof(machine->sound[0])); + return; + } + + fatalerror("Can't find sound '%s'!\n", tag); +} + + +/*------------------------------------------------- + driver_add_screen - add a screen during + machine driver expansion +-------------------------------------------------*/ + +screen_config *driver_add_screen(machine_config *machine, const char *tag, int palbase) +{ + int screennum; + + for (screennum = 0; screennum < MAX_SCREENS; screennum++) + if (machine->screen[screennum].tag == NULL) + { + machine->screen[screennum].tag = tag; + machine->screen[screennum].palette_base = palbase; + return &machine->screen[screennum]; + } + + fatalerror("Out of screens!\n"); + return NULL; +} + + +/*------------------------------------------------- + driver_find_screen - find a tagged screen + during machine driver expansion +-------------------------------------------------*/ + +screen_config *driver_find_screen(machine_config *machine, const char *tag) +{ + int screennum; + + for (screennum = 0; screennum < MAX_SCREENS; screennum++) + if (machine->screen[screennum].tag && strcmp(machine->screen[screennum].tag, tag) == 0) + return &machine->screen[screennum]; + + fatalerror("Can't find screen '%s'!\n", tag); + return NULL; +} + + +/*------------------------------------------------- + driver_remove_screen - remove a tagged screen + during machine driver expansion +-------------------------------------------------*/ + +void driver_remove_screen(machine_config *machine, const char *tag) +{ + int screennum; + + for (screennum = 0; screennum < MAX_SCREENS; screennum++) + if (machine->screen[screennum].tag && strcmp(machine->screen[screennum].tag, tag) == 0) + { + memmove(&machine->screen[screennum], &machine->screen[screennum + 1], sizeof(machine->screen[0]) * (MAX_SCREENS - screennum - 1)); + memset(&machine->screen[MAX_SCREENS - 1], 0, sizeof(machine->screen[0])); + return; + } + + fatalerror("Can't find screen '%s'!\n", tag); +} + + +/*------------------------------------------------- + driver_get_name - return a pointer to a + driver given its name +-------------------------------------------------*/ + +const game_driver *driver_get_name(const char *name) +{ + int lurnum, drvnum; + + /* scan the LRU list first */ + for (lurnum = 0; lurnum < DRIVER_LRU_SIZE; lurnum++) + if (mame_stricmp(drivers[driver_lru[lurnum]]->name, name) == 0) + { + /* if not first, swap with the head */ + if (lurnum != 0) + { + int temp = driver_lru[0]; + driver_lru[0] = driver_lru[lurnum]; + driver_lru[lurnum] = temp; + } + return drivers[driver_lru[0]]; + } + + /* scan for a match in the drivers -- slow! */ + for (drvnum = 0; drivers[drvnum] != NULL; drvnum++) + if (mame_stricmp(drivers[drvnum]->name, name) == 0) + { + memmove((void *)&driver_lru[1], (void *)&driver_lru[0], sizeof(driver_lru[0]) * (DRIVER_LRU_SIZE - 1)); + driver_lru[0] = drvnum; + return drivers[drvnum]; + } + + return NULL; +} + + +/*------------------------------------------------- + driver_get_clone - return a pointer to the + clone of a game driver. +-------------------------------------------------*/ + +const game_driver *driver_get_clone(const game_driver *driver) +{ + /* if no clone, easy out */ + if (driver->parent == NULL || (driver->parent[0] == '0' && driver->parent[1] == 0)) + return NULL; + + /* convert the name to a game_driver */ + return driver_get_name(driver->parent); +} + + +/*------------------------------------------------- + driver_list_get_approx_matches - find the best + n matches to a driver name. +-------------------------------------------------*/ + +void driver_list_get_approx_matches(const game_driver * const driverlist[], const char *name, int matches, const game_driver **list) +{ +#undef rand + + int matchnum, drvnum; + int *penalty; + + /* if no name, pick random entries */ + if (name == NULL || name[0] == 0) + { + const game_driver **templist; + int driver_count; + int shufnum; + + /* allocate a temporary list */ + templist = malloc_or_die(driver_list_get_count(driverlist) * sizeof(*templist)); + + /* build up a list of valid entries */ + for (drvnum = driver_count = 0; driverlist[drvnum] != NULL; drvnum++) + if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) == 0) + templist[driver_count++] = driverlist[drvnum]; + + /* seed the RNG first */ + srand(osd_ticks()); + + /* shuffle */ + for (shufnum = 0; shufnum < 4 * driver_count; shufnum++) + { + int item1 = rand() % driver_count; + int item2 = rand() % driver_count; + const game_driver *temp; + + temp = templist[item1]; + templist[item1] = templist[item2]; + templist[item2] = temp; + } + + /* copy out the first few entries */ + for (matchnum = 0; matchnum < matches; matchnum++) + list[matchnum] = templist[matchnum % driver_count]; + + free((void *)templist); + return; + } + + /* allocate some temp memory */ + penalty = malloc_or_die(matches * sizeof(*penalty)); + + /* initialize everyone's states */ + for (matchnum = 0; matchnum < matches; matchnum++) + { + penalty[matchnum] = 9999; + list[matchnum] = NULL; + } + + /* scan the entire drivers array */ + for (drvnum = 0; driverlist[drvnum] != NULL; drvnum++) + { + int curpenalty, tmp; + + /* skip things that can't run */ + if ((driverlist[drvnum]->flags & GAME_NO_STANDALONE) != 0) + continue; + + /* pick the best match between driver name and description */ + curpenalty = penalty_compare(name, driverlist[drvnum]->description); + tmp = penalty_compare(name, driverlist[drvnum]->name); + curpenalty = MIN(curpenalty, tmp); + + /* insert into the sorted table of matches */ + for (matchnum = matches - 1; matchnum >= 0; matchnum--) + { + /* stop if we're worse than the current entry */ + if (curpenalty >= penalty[matchnum]) + break; + + /* as lng as this isn't the last entry, bump this one down */ + if (matchnum < matches - 1) + { + penalty[matchnum + 1] = penalty[matchnum]; + list[matchnum + 1] = list[matchnum]; + } + list[matchnum] = driverlist[drvnum]; + penalty[matchnum] = curpenalty; + } + } + + /* free our temp memory */ + free(penalty); +} + + +/*------------------------------------------------- + penalty_compare - compare two strings for + closeness and assign a score. +-------------------------------------------------*/ + +static int penalty_compare(const char *source, const char *target) +{ + int gaps = 1; + int last = TRUE; + + /* scan the strings */ + for ( ; *source && *target; target++) + { + /* do a case insensitive match */ + int match = (tolower(*source) == tolower(*target)); + + /* if we matched, advance the source */ + if (match) + source++; + + /* if the match state changed, count gaps */ + if (match != last) + { + last = match; + if (!match) + gaps++; + } + } + + /* penalty if short string does not completely fit in */ + for ( ; *source; source++) + gaps++; + + /* if we matched perfectly, gaps == 0 */ + if (gaps == 1 && *source == 0 && *target == 0) + gaps = 0; + + return gaps; +} + + +/*------------------------------------------------- + driver_list_get_count - returns the amount of + drivers +-------------------------------------------------*/ + +int driver_list_get_count(const game_driver * const driverlist[]) +{ + int count; + + for (count = 0; driverlist[count] != NULL; count++) ; + return count; +} |