summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpuexec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpuexec.c')
-rw-r--r--src/emu/cpuexec.c1998
1 files changed, 0 insertions, 1998 deletions
diff --git a/src/emu/cpuexec.c b/src/emu/cpuexec.c
deleted file mode 100644
index 82f73d49888..00000000000
--- a/src/emu/cpuexec.c
+++ /dev/null
@@ -1,1998 +0,0 @@
-/***************************************************************************
-
- cpuexec.c
-
- Core multi-CPU execution engine.
-
- Copyright Nicola Salmoria and the MAME Team.
- Visit http://mamedev.org for licensing and usage restrictions.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "profiler.h"
-#include "debugger.h"
-
-
-/***************************************************************************
- DEBUGGING
-***************************************************************************/
-
-#define VERBOSE 0
-
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
-
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* internal trigger IDs */
-enum
-{
- TRIGGER_INT = -2000,
- TRIGGER_YIELDTIME = -3000,
- TRIGGER_SUSPENDTIME = -4000
-};
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* internal information about the state of inputs */
-typedef struct _cpu_input_data cpu_input_data;
-struct _cpu_input_data
-{
- INT32 vector; /* most recently written vector */
- INT32 curvector; /* most recently processed vector */
- UINT8 curstate; /* most recently processed state */
- INT32 queue[MAX_INPUT_EVENTS]; /* queue of pending events */
- int qindex; /* index within the queue */
-};
-
-
-/* internal data hanging off of the classtoken */
-typedef struct _cpu_class_data cpu_class_data;
-struct _cpu_class_data
-{
- /* execution lists */
- running_device *device; /* pointer back to our device */
- cpu_class_data *next; /* pointer to the next CPU to execute, in order */
- cpu_execute_func execute; /* execute function pointer */
-
- /* cycle counting and executing */
- int profiler; /* profiler tag */
- int * icount; /* pointer to the icount */
- int cycles_running; /* number of cycles we are executing */
- int cycles_stolen; /* number of cycles we artificially stole */
-
- /* input states and IRQ callbacks */
- cpu_irq_callback driver_irq; /* driver-specific IRQ callback */
- cpu_input_data input[MAX_INPUT_LINES]; /* data about inputs */
-
- /* suspend states */
- UINT8 suspend; /* suspend reason mask (0 = not suspended) */
- UINT8 nextsuspend; /* pending suspend reason mask */
- UINT8 eatcycles; /* true if we eat cycles while suspended */
- UINT8 nexteatcycles; /* pending value */
- INT32 trigger; /* pending trigger to release a trigger suspension */
- INT32 inttrigger; /* interrupt trigger index */
-
- /* clock and timing information */
- UINT64 totalcycles; /* total CPU cycles executed */
- attotime localtime; /* local time, relative to the timer system's global time */
- INT32 clock; /* current active clock */
- double clockscale; /* current active clock scale factor */
- INT32 divisor; /* 32-bit attoseconds_per_cycle divisor */
- UINT8 divshift; /* right shift amount to fit the divisor into 32 bits */
- emu_timer * timedint_timer; /* reference to this CPU's periodic interrupt timer */
- UINT32 cycles_per_second; /* cycles per second, adjusted for multipliers */
- attoseconds_t attoseconds_per_cycle; /* attoseconds per adjusted clock cycle */
-
- /* internal state reflection */
- const cpu_state_table *state; /* pointer to the base table */
- const cpu_state_entry *regstate[MAX_REGS];/* pointer to the state entry for each register */
-
- /* these below are hacks to support multiple interrupts per frame */
- INT32 iloops; /* number of interrupts remaining this frame */
- emu_timer * partial_frame_timer; /* the timer that triggers partial frame interrupts */
- attotime partial_frame_period; /* the length of one partial frame for interrupt purposes */
-};
-
-
-/* global data stored in the machine */
-/* In mame.h: typedef struct _cpuexec_private cpuexec_private; */
-struct _cpuexec_private
-{
- running_device *executingcpu; /* pointer to the currently executing CPU */
- cpu_class_data *executelist; /* execution list; suspended CPUs are at the back */
- char statebuf[256]; /* string buffer containing state description */
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-static void update_clock_information(running_device *device);
-static void compute_perfect_interleave(running_machine *machine);
-static void on_vblank(running_device *device, void *param, int vblank_state);
-static TIMER_CALLBACK( trigger_partial_frame_interrupt );
-static TIMER_CALLBACK( trigger_periodic_interrupt );
-static TIMER_CALLBACK( triggertime_callback );
-static TIMER_CALLBACK( empty_event_queue );
-static IRQ_CALLBACK( standard_irq_callback );
-static void register_save_states(running_device *device);
-static void rebuild_execute_list(running_machine *machine);
-static UINT64 get_register_value(running_device *device, void *baseptr, const cpu_state_entry *entry);
-static void set_register_value(running_device *device, void *baseptr, const cpu_state_entry *entry, UINT64 value);
-static void get_register_string_value(running_device *device, void *baseptr, const cpu_state_entry *entry, char *dest);
-#ifdef UNUSED_FUNCTION
-static int get_register_string_max_width(running_device *device, void *baseptr, const cpu_state_entry *entry);
-#endif
-
-
-
-/***************************************************************************
- MACROS
-***************************************************************************/
-
-/* these are macros to ensure inlining in cpuexec_timeslice */
-#define ATTOTIME_LT(a,b) ((a).seconds < (b).seconds || ((a).seconds == (b).seconds && (a).attoseconds < (b).attoseconds))
-#define ATTOTIME_NORMALIZE(a) do { if ((a).attoseconds >= ATTOSECONDS_PER_SECOND) { (a).seconds++; (a).attoseconds -= ATTOSECONDS_PER_SECOND; } } while (0)
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- get_class_data - return a pointer to the
- class data
--------------------------------------------------*/
-
-INLINE cpu_class_data *get_class_data(running_device *device)
-{
- assert(device != NULL);
- assert(device->devclass == DEVICE_CLASS_CPU_CHIP);
- assert(device->token != NULL);
- return (cpu_class_data *)cpu_get_class_header(device) - 1;
-}
-
-
-/*-------------------------------------------------
- get_minimum_quantum - return the minimum
- quantum required for a given CPU device
--------------------------------------------------*/
-
-INLINE attoseconds_t get_minimum_quantum(running_device *device)
-{
- attoseconds_t basetick = 0;
-
- /* fetch the base clock from the classdata if present */
- if (device->token != NULL)
- basetick = get_class_data(device)->attoseconds_per_cycle;
-
- /* otherwise compute it from the raw data */
- if (basetick == 0)
- {
- UINT32 baseclock = (UINT64)device->clock * cpu_get_clock_multiplier(device) / cpu_get_clock_divider(device);
- basetick = HZ_TO_ATTOSECONDS(baseclock);
- }
-
- /* apply the minimum cycle count */
- return basetick * cpu_get_min_cycles(device);
-}
-
-
-/*-------------------------------------------------
- suspend_until_trigger - suspend execution
- until the given trigger fires
--------------------------------------------------*/
-
-INLINE void suspend_until_trigger(running_device *device, int trigger, int eatcycles)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* suspend the CPU immediately if it's not already */
- cpu_suspend(device, SUSPEND_REASON_TRIGGER, eatcycles);
-
- /* set the trigger */
- classdata->trigger = trigger;
-}
-
-
-
-/***************************************************************************
- CORE CPU EXECUTION
-***************************************************************************/
-
-/*-------------------------------------------------
- cpuexec_init - initialize internal states of
- all CPUs
--------------------------------------------------*/
-
-void cpuexec_init(running_machine *machine)
-{
- attotime min_quantum;
-
- /* allocate global state */
- machine->cpuexec_data = auto_alloc_clear(machine, cpuexec_private);
-
- /* set the core scheduling quantum */
- min_quantum = machine->config->minimum_quantum;
- if (attotime_compare(min_quantum, attotime_zero) == 0)
- min_quantum = ATTOTIME_IN_HZ(60);
- if (machine->config->perfect_cpu_quantum != NULL)
- {
- running_device *cpu = machine->device(machine->config->perfect_cpu_quantum);
- attotime cpu_quantum;
-
- if (cpu == NULL)
- fatalerror("CPU '%s' specified for perfect interleave is not present!", machine->config->perfect_cpu_quantum);
- cpu_quantum = attotime_make(0, get_minimum_quantum(cpu));
- min_quantum = attotime_min(cpu_quantum, min_quantum);
- }
- assert(min_quantum.seconds == 0);
- timer_add_scheduling_quantum(machine, min_quantum.attoseconds, attotime_never);
-}
-
-
-/*-------------------------------------------------
- cpuexec_timeslice - execute all CPUs for a
- single timeslice
--------------------------------------------------*/
-
-void cpuexec_timeslice(running_machine *machine)
-{
- int call_debugger = ((machine->debug_flags & DEBUG_FLAG_ENABLED) != 0);
- timer_execution_state *timerexec = timer_get_execution_state(machine);
- cpuexec_private *global = machine->cpuexec_data;
- int ran;
-
- /* build the execution list if we don't have one yet */
- if (global->executelist == NULL)
- rebuild_execute_list(machine);
-
- /* loop until we hit the next timer */
- while (ATTOTIME_LT(timerexec->basetime, timerexec->nextfire))
- {
- cpu_class_data *classdata;
- UINT32 suspendchanged;
- attotime target;
-
- /* by default, assume our target is the end of the next quantum */
- target.seconds = timerexec->basetime.seconds;
- target.attoseconds = timerexec->basetime.attoseconds + timerexec->curquantum;
- ATTOTIME_NORMALIZE(target);
-
- /* however, if the next timer is going to fire before then, override */
- assert(attotime_sub(timerexec->nextfire, target).seconds <= 0);
- if (ATTOTIME_LT(timerexec->nextfire, target))
- target = timerexec->nextfire;
-
- LOG(("------------------\n"));
- LOG(("cpu_timeslice: target = %s\n", attotime_string(target, 9)));
-
- /* apply pending suspension changes */
- suspendchanged = 0;
- for (classdata = global->executelist; classdata != NULL; classdata = classdata->next)
- {
- suspendchanged |= (classdata->suspend ^ classdata->nextsuspend);
- classdata->suspend = classdata->nextsuspend;
- classdata->nextsuspend &= ~SUSPEND_REASON_TIMESLICE;
- classdata->eatcycles = classdata->nexteatcycles;
- }
-
- /* recompute the execute list if any CPUs changed their suspension state */
- if (suspendchanged != 0)
- rebuild_execute_list(machine);
-
- /* loop over non-suspended CPUs */
- for (classdata = global->executelist; classdata != NULL; classdata = classdata->next)
- {
- /* only process if our target is later than the CPU's current time (coarse check) */
- if (target.seconds >= classdata->localtime.seconds)
- {
- attoseconds_t delta, actualdelta;
-
- /* compute how many attoseconds to execute this CPU */
- delta = target.attoseconds - classdata->localtime.attoseconds;
- if (delta < 0 && target.seconds > classdata->localtime.seconds)
- delta += ATTOSECONDS_PER_SECOND;
- assert(delta == attotime_to_attoseconds(attotime_sub(target, classdata->localtime)));
-
- /* if we have enough for at least 1 cycle, do the math */
- if (delta >= classdata->attoseconds_per_cycle)
- {
- /* compute how many cycles we want to execute */
- ran = classdata->cycles_running = divu_64x32((UINT64)delta >> classdata->divshift, classdata->divisor);
- LOG((" cpu '%s': %d cycles\n", classdata->device->tag(), classdata->cycles_running));
-
- /* if we're not suspended, actually execute */
- if (classdata->suspend == 0)
- {
- profiler_mark_start(classdata->profiler);
-
- /* note that this global variable cycles_stolen can be modified */
- /* via the call to cpu_execute */
- classdata->cycles_stolen = 0;
- global->executingcpu = classdata->device;
- *classdata->icount = classdata->cycles_running;
- if (!call_debugger)
- ran = (*classdata->execute)(classdata->device, classdata->cycles_running);
- else
- {
- debugger_start_cpu_hook(classdata->device, target);
- ran = (*classdata->execute)(classdata->device, classdata->cycles_running);
- debugger_stop_cpu_hook(classdata->device);
- }
-
- /* adjust for any cycles we took back */
- assert(ran >= classdata->cycles_stolen);
- ran -= classdata->cycles_stolen;
- profiler_mark_end();
- }
-
- /* account for these cycles */
- classdata->totalcycles += ran;
-
- /* update the local time for this CPU */
- actualdelta = classdata->attoseconds_per_cycle * ran;
- classdata->localtime.attoseconds += actualdelta;
- ATTOTIME_NORMALIZE(classdata->localtime);
- LOG((" %d ran, %d total, time = %s\n", ran, (INT32)classdata->totalcycles, attotime_string(classdata->localtime, 9)));
-
- /* if the new local CPU time is less than our target, move the target up */
- if (ATTOTIME_LT(classdata->localtime, target))
- {
- assert(attotime_compare(classdata->localtime, target) < 0);
- target = classdata->localtime;
-
- /* however, if this puts us before the base, clamp to the base as a minimum */
- if (ATTOTIME_LT(target, timerexec->basetime))
- {
- assert(attotime_compare(target, timerexec->basetime) < 0);
- target = timerexec->basetime;
- }
- LOG((" (new target)\n"));
- }
- }
- }
- }
- global->executingcpu = NULL;
-
- /* update the base time */
- timerexec->basetime = target;
- }
-
- /* execute timers */
- timer_execute_timers(machine);
-}
-
-
-/*-------------------------------------------------
- cpuexec_boost_interleave - temporarily boosts
- the interleave factor
--------------------------------------------------*/
-
-void cpuexec_boost_interleave(running_machine *machine, attotime timeslice_time, attotime boost_duration)
-{
- /* ignore timeslices > 1 second */
- if (timeslice_time.seconds > 0)
- return;
- timer_add_scheduling_quantum(machine, timeslice_time.attoseconds, boost_duration);
-}
-
-
-
-/***************************************************************************
- GLOBAL HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- cpuexec_abort_timeslice - abort execution
- for the current timeslice
--------------------------------------------------*/
-
-void cpuexec_abort_timeslice(running_machine *machine)
-{
- running_device *executingcpu = machine->cpuexec_data->executingcpu;
- if (executingcpu != NULL)
- cpu_abort_timeslice(executingcpu);
-}
-
-
-/*-------------------------------------------------
- cpuexec_describe_context - return a string
- describing which CPUs are currently executing
- and their PC
--------------------------------------------------*/
-
-const char *cpuexec_describe_context(running_machine *machine)
-{
- cpuexec_private *global = machine->cpuexec_data;
- running_device *executingcpu = global->executingcpu;
-
- /* if we have an executing CPU, output data */
- if (executingcpu != NULL)
- {
- const address_space *space = cpu_get_address_space(executingcpu, ADDRESS_SPACE_PROGRAM);
- sprintf(global->statebuf, "'%s' (%s)", executingcpu->tag(), core_i64_hex_format(cpu_get_pc(executingcpu), space->logaddrchars));
- }
- else
- strcpy(global->statebuf, "(no context)");
-
- return global->statebuf;
-}
-
-
-
-/***************************************************************************
- CPU DEVICE INTERFACE
-***************************************************************************/
-
-/*-------------------------------------------------
- device_start_cpu - device start callback
--------------------------------------------------*/
-
-static DEVICE_START( cpu )
-{
- int index = cpu_get_index(device);
- cpu_class_header *header;
- cpu_class_data *classdata;
- const cpu_config *config;
- cpu_init_func init;
- int num_regs;
- int line;
-
- /* validate some basic stuff */
- assert(device != NULL);
- assert(device->baseconfig().inline_config != NULL);
- assert(device->machine != NULL);
- assert(device->machine->config != NULL);
-
- /* get pointers to our data */
- config = (const cpu_config *)device->baseconfig().inline_config;
- header = cpu_get_class_header(device);
- classdata = get_class_data(device);
-
- /* build the header */
- header->debug = NULL;
- header->set_info = (cpu_set_info_func)device->get_config_fct(CPUINFO_FCT_SET_INFO);
-
- /* fill in the input states and IRQ callback information */
- for (line = 0; line < ARRAY_LENGTH(classdata->input); line++)
- {
- cpu_input_data *inputline = &classdata->input[line];
- /* vector and curvector are initialized later */
- inputline->curstate = CLEAR_LINE;
- inputline->qindex = 0;
- }
-
- /* fill in the suspend states */
- classdata->device = device;
- classdata->execute = (cpu_execute_func)device->get_config_fct(CPUINFO_FCT_EXECUTE);
- classdata->profiler = index + PROFILER_CPU_FIRST;
- classdata->suspend = SUSPEND_REASON_RESET;
- classdata->inttrigger = index + TRIGGER_INT;
-
- /* fill in the clock and timing information */
- classdata->clock = (UINT64)device->clock * cpu_get_clock_multiplier(device) / cpu_get_clock_divider(device);
- classdata->clockscale = 1.0;
-
- /* allocate timers if we need them */
- if (config->vblank_interrupts_per_frame > 1)
- classdata->partial_frame_timer = timer_alloc(device->machine, trigger_partial_frame_interrupt, (void *)device);
- if (config->timed_interrupt_period != 0)
- classdata->timedint_timer = timer_alloc(device->machine, trigger_periodic_interrupt, (void *)device);
-
- /* initialize this CPU */
- num_regs = state_save_get_reg_count(device->machine);
- init = (cpu_init_func)device->get_config_fct(CPUINFO_FCT_INIT);
- (*init)(device, standard_irq_callback);
- num_regs = state_save_get_reg_count(device->machine) - num_regs;
-
- /* fetch post-initialization data */
- classdata->icount = cpu_get_icount_ptr(device);
- for (line = 0; line < ARRAY_LENGTH(classdata->input); line++)
- {
- cpu_input_data *inputline = &classdata->input[line];
- inputline->vector = cpu_get_default_irq_vector(device);
- inputline->curvector = inputline->vector;
- }
- update_clock_information(device);
-
- /* fetch information about the CPU states */
- classdata->state = cpu_get_state_table(device);
- if (classdata->state != NULL)
- {
- int stateindex;
-
- /* loop over all states specified, and work with any that apply */
- for (stateindex = 0; stateindex < classdata->state->entrycount; stateindex++)
- {
- const cpu_state_entry *entry = &classdata->state->entrylist[stateindex];
- if (entry->validmask == 0 || (entry->validmask & classdata->state->subtypemask) != 0)
- {
- assert(entry->index < MAX_REGS);
- assert(classdata->regstate[entry->index] == NULL);
- classdata->regstate[entry->index] = entry;
- }
- }
- }
-
- /* if no state registered for saving, we can't save */
- if (num_regs == 0)
- {
- logerror("CPU '%s' did not register any state to save!\n", device->tag());
- if (device->machine->gamedrv->flags & GAME_SUPPORTS_SAVE)
- fatalerror("CPU '%s' did not register any state to save!", device->tag());
- }
-
- /* register some internal states as well */
- register_save_states(device);
-}
-
-
-/*-------------------------------------------------
- device_reset_cpu - device reset callback
--------------------------------------------------*/
-
-static DEVICE_RESET( cpu )
-{
- cpu_class_data *classdata = get_class_data(device);
- const cpu_config *config = (const cpu_config *)device->baseconfig().inline_config;
- cpu_reset_func reset;
- int line;
-
- /* enable all CPUs (except for disabled CPUs) */
- if (!(config->flags & CPU_DISABLE))
- cpu_resume(device, SUSPEND_ANY_REASON);
- else
- cpu_suspend(device, SUSPEND_REASON_DISABLE, 1);
-
- /* reset the total number of cycles */
- classdata->totalcycles = 0;
-
- /* then reset the CPU directly */
- reset = (cpu_reset_func)device->get_config_fct(CPUINFO_FCT_RESET);
- if (reset != NULL)
- (*reset)(device);
-
- /* reset the interrupt vectors and queues */
- for (line = 0; line < ARRAY_LENGTH(classdata->input); line++)
- {
- cpu_input_data *inputline = &classdata->input[line];
- inputline->vector = cpu_get_default_irq_vector(device);
- inputline->qindex = 0;
- }
-
- /* reconfingure VBLANK interrupts */
- if (config->vblank_interrupts_per_frame > 0 || config->vblank_interrupt_screen != NULL)
- {
- running_device *screen;
-
- /* get the screen that will trigger the VBLANK */
-
- /* new style - use screen tag directly */
- if (config->vblank_interrupt_screen != NULL)
- screen = device->machine->device(config->vblank_interrupt_screen);
-
- /* old style 'hack' setup - use screen #0 */
- else
- screen = video_screen_first(device->machine);
-
- assert(screen != NULL);
- video_screen_register_vblank_callback(screen, on_vblank, NULL);
- }
-
- /* reconfigure periodic interrupts */
- if (config->timed_interrupt_period != 0)
- {
- attotime timedint_period = UINT64_ATTOTIME_TO_ATTOTIME(config->timed_interrupt_period);
- assert(classdata->timedint_timer != NULL);
- timer_adjust_periodic(classdata->timedint_timer, timedint_period, 0, timedint_period);
- }
-}
-
-
-/*-------------------------------------------------
- device_stop_cpu - device stop callback
--------------------------------------------------*/
-
-static DEVICE_STOP( cpu )
-{
- cpu_exit_func exit;
-
- /* call the CPU's exit function if present */
- exit = (cpu_exit_func)device->get_config_fct(CPUINFO_FCT_EXIT);
- if (exit != NULL)
- (*exit)(device);
-}
-
-
-/*-------------------------------------------------
- cpu_set_info - device set info callback
--------------------------------------------------*/
-
-void cpu_set_info(running_device *device, UINT32 state, UINT64 value)
-{
- cpu_class_header *header = cpu_get_class_header(device);
- cpu_set_info_func set_info;
- cpuinfo cinfo;
-
- /* if we are live and have a header, save ourself a call */
- if (header != NULL)
- set_info = header->set_info;
- else
- set_info = (cpu_set_info_func)device->get_config_fct(CPUINFO_FCT_SET_INFO);
-
- switch (state)
- {
- /* no parameters to set */
-
- default:
- /* if we have a state pointer, we can handle some stuff for free */
- if (device->token != NULL)
- {
- const cpu_class_data *classdata = get_class_data(device);
- if (classdata->state != NULL)
- {
- if (state >= CPUINFO_INT_REGISTER && state <= CPUINFO_INT_REGISTER_LAST)
- {
- set_register_value(device, classdata->state->baseptr, classdata->regstate[state - CPUINFO_INT_REGISTER], value);
- return;
- }
- }
- }
-
- /* integer data */
- assert(state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST);
- if (state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST)
- {
- cinfo.i = value;
- (*set_info)(device, state, &cinfo);
- }
- break;
- }
-}
-
-
-/*-------------------------------------------------
- cpu_get_info - device get info
- callback
--------------------------------------------------*/
-
-static DEVICE_GET_RUNTIME_INFO( cpu )
-{
- const cpu_config *config = (device != NULL) ? (const cpu_config *)device->baseconfig().inline_config : NULL;
- cpuinfo cinfo = { 0 };
-
- /* if we don't have a device pointer, ignore everything else */
- if (device == NULL)
- return;
-
- /* if we have a state pointer, we can handle some stuff for free */
- if (device->token != NULL)
- {
- const cpu_class_data *classdata = get_class_data(device);
- if (classdata->state != NULL)
- {
- if (state >= CPUINFO_INT_REGISTER && state <= CPUINFO_INT_REGISTER_LAST)
- {
- info->i = get_register_value(device, classdata->state->baseptr, classdata->regstate[state - CPUINFO_INT_REGISTER]);
- return;
- }
- else if (state >= CPUINFO_STR_REGISTER && state <= CPUINFO_STR_REGISTER_LAST)
- {
- cinfo.s = info->s;
- get_register_string_value(device, classdata->state->baseptr, classdata->regstate[state - CPUINFO_STR_REGISTER], cinfo.s);
- info->s = cinfo.s;
- return;
- }
- }
- }
-
- /* integer data */
- if (state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST)
- {
- cinfo.i = info->i;
- (*config->type)(&device->baseconfig(), device, state, &cinfo);
- info->i = cinfo.i;
- }
-
- /* pointer data */
- else if ((state >= DEVINFO_PTR_FIRST && state <= DEVINFO_PTR_LAST) ||
- (state >= DEVINFO_FCT_FIRST && state <= DEVINFO_FCT_LAST) ||
- (state >= DEVINFO_STR_FIRST && state <= DEVINFO_STR_LAST))
- {
- cinfo.p = info->p;
- (*config->type)(&device->baseconfig(), device, state, &cinfo);
- info->p = cinfo.p;
- }
-}
-
-
-DEVICE_GET_INFO( cpu )
-{
- const cpu_config *config = (const cpu_config *)device->inline_config;
- cpuinfo cinfo = { 0 };
-
- switch (state)
- {
- /* --- the following bits of info are returned as 64-bit signed integers --- */
- case DEVINFO_INT_TOKEN_BYTES:
- cinfo.i = 0;
- (*config->type)(device, NULL, CPUINFO_INT_CONTEXT_SIZE, &cinfo);
- info->i = cinfo.i + sizeof(cpu_class_data) + sizeof(cpu_class_header);
- break;
-
- case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(cpu_config); break;
- case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_CPU_CHIP; break;
-
- /* --- the following bits of info are returned as pointers to data or functions --- */
- case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(cpu); break;
- case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME(cpu); break;
- case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(cpu); break;
- case DEVINFO_FCT_GET_RUNTIME_INFO: info->get_runtime_info = DEVICE_GET_RUNTIME_INFO_NAME(cpu); break;
-
- default:
- /* integer data */
- if (state >= DEVINFO_INT_FIRST && state <= DEVINFO_INT_LAST)
- {
- cinfo.i = info->i;
- (*config->type)(device, NULL, state, &cinfo);
- info->i = cinfo.i;
- }
-
- /* pointer data */
- else if ((state >= DEVINFO_PTR_FIRST && state <= DEVINFO_PTR_LAST) ||
- (state >= DEVINFO_FCT_FIRST && state <= DEVINFO_FCT_LAST) ||
- (state >= DEVINFO_STR_FIRST && state <= DEVINFO_STR_LAST))
- {
- cinfo.p = info->p;
- (*config->type)(device, NULL, state, &cinfo);
- info->p = cinfo.p;
- }
- break;
- }
-}
-
-
-
-/***************************************************************************
- CPU SCHEDULING
-***************************************************************************/
-
-/*-------------------------------------------------
- cpu_suspend - set a suspend reason for the
- given CPU
--------------------------------------------------*/
-
-void cpu_suspend(running_device *device, int reason, int eatcycles)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* set the suspend reason and eat cycles flag */
- classdata->nextsuspend |= reason;
- classdata->nexteatcycles = eatcycles;
-
- /* if we're active, synchronize */
- cpu_abort_timeslice(device);
-}
-
-
-/*-------------------------------------------------
- cpu_resume - clear a suspend reason for the
- given CPU
--------------------------------------------------*/
-
-void cpu_resume(running_device *device, int reason)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* clear the suspend reason and eat cycles flag */
- classdata->nextsuspend &= ~reason;
-
- /* if we're active, synchronize */
- cpu_abort_timeslice(device);
-}
-
-
-/*-------------------------------------------------
- cpu_is_executing - return TRUE if the given
- CPU is within its execute function
--------------------------------------------------*/
-
-int cpu_is_executing(running_device *device)
-{
- return (device == device->machine->cpuexec_data->executingcpu);
-}
-
-
-/*-------------------------------------------------
- cpu_is_suspended - returns TRUE if the
- given CPU is suspended for any of the given
- reasons
--------------------------------------------------*/
-
-int cpu_is_suspended(running_device *device, int reason)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* return true if the given reason is indicated */
- return ((classdata->nextsuspend & reason) != 0);
-}
-
-
-
-/***************************************************************************
- CPU CLOCK MANAGEMENT
-***************************************************************************/
-
-/*-------------------------------------------------
- cpu_get_clock - gets the given CPU's
- clock speed
--------------------------------------------------*/
-
-int cpu_get_clock(running_device *device)
-{
- cpu_class_data *classdata;
-
- /* if we haven't been started yet, compute it manually */
- if (device->token == NULL)
- return (UINT64)device->clock * cpu_get_clock_multiplier(device) / cpu_get_clock_divider(device);
-
- /* return the current clock value */
- classdata = get_class_data(device);
- return classdata->clock;
-}
-
-
-/*-------------------------------------------------
- cpu_set_clock - sets the given CPU's
- clock speed
--------------------------------------------------*/
-
-void cpu_set_clock(running_device *device, int clock)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* set the clock and update the information */
- classdata->clock = clock;
- update_clock_information(device);
-}
-
-
-/*-------------------------------------------------
- cpu_get_clockscale - returns the current
- scaling factor for a CPU's clock speed
--------------------------------------------------*/
-
-double cpu_get_clockscale(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* return the current clock scale factor */
- return classdata->clockscale;
-}
-
-
-/*-------------------------------------------------
- cpu_set_clockscale - sets the current
- scaling factor for a CPU's clock speed
--------------------------------------------------*/
-
-void cpu_set_clockscale(running_device *device, double clockscale)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* set the scale factor and update the information */
- classdata->clockscale = clockscale;
- update_clock_information(device);
-}
-
-
-/*-------------------------------------------------
- cpu_clocks_to_attotime - converts a number of
- clock ticks to an attotime
--------------------------------------------------*/
-
-attotime cpu_clocks_to_attotime(running_device *device, UINT64 clocks)
-{
- cpu_class_data *classdata = get_class_data(device);
- if (clocks < classdata->cycles_per_second)
- return attotime_make(0, clocks * classdata->attoseconds_per_cycle);
- else
- {
- UINT32 remainder;
- UINT32 quotient = divu_64x32_rem(clocks, classdata->cycles_per_second, &remainder);
- return attotime_make(quotient, (UINT64)remainder * (UINT64)classdata->attoseconds_per_cycle);
- }
-}
-
-
-/*-------------------------------------------------
- cpu_attotime_to_clocks - converts a duration
- as attotime to CPU clock ticks
--------------------------------------------------*/
-
-UINT64 cpu_attotime_to_clocks(running_device *device, attotime duration)
-{
- cpu_class_data *classdata = get_class_data(device);
- return mulu_32x32(duration.seconds, classdata->cycles_per_second) + (UINT64)duration.attoseconds / (UINT64)classdata->attoseconds_per_cycle;
-}
-
-
-
-/***************************************************************************
- CPU TIMING
-***************************************************************************/
-
-/*-------------------------------------------------
- cpu_get_local_time - returns the current
- local time for a CPU
--------------------------------------------------*/
-
-attotime cpu_get_local_time(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
- attotime result;
-
- /* if we're active, add in the time from the current slice */
- result = classdata->localtime;
- if (device == device->machine->cpuexec_data->executingcpu)
- {
- int cycles = classdata->cycles_running - *classdata->icount;
- result = attotime_add(result, cpu_clocks_to_attotime(device, cycles));
- }
- return result;
-}
-
-
-/*-------------------------------------------------
- cpuexec_override_local_time - overrides the
- given time with the executing CPU's local
- time, if present (this function is private
- to timer.c)
--------------------------------------------------*/
-
-attotime cpuexec_override_local_time(running_machine *machine, attotime default_time)
-{
- if (machine->cpuexec_data != NULL && machine->cpuexec_data->executingcpu != NULL)
- return cpu_get_local_time(machine->cpuexec_data->executingcpu);
- return default_time;
-}
-
-
-/*-------------------------------------------------
- cpu_get_total_cycles - return the total
- number of CPU cycles executed on the active
- CPU
--------------------------------------------------*/
-
-UINT64 cpu_get_total_cycles(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- if (device == device->machine->cpuexec_data->executingcpu)
- return classdata->totalcycles + classdata->cycles_running - *classdata->icount;
- else
- return classdata->totalcycles;
-}
-
-
-/*-------------------------------------------------
- cpu_eat_cycles - safely eats cycles so
- we don't cross a timeslice boundary
--------------------------------------------------*/
-
-void cpu_eat_cycles(running_device *device, int cycles)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* ignore if not the executing CPU */
- if (device != device->machine->cpuexec_data->executingcpu)
- return;
-
- if (cycles > *classdata->icount)
- cycles = *classdata->icount;
- *classdata->icount -= cycles;
-}
-
-
-/*-------------------------------------------------
- cpu_adjust_icount - apply a +/- to the current
- icount
--------------------------------------------------*/
-
-void cpu_adjust_icount(running_device *device, int delta)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* ignore if not the executing CPU */
- if (device != device->machine->cpuexec_data->executingcpu)
- return;
-
- *classdata->icount += delta;
-}
-
-
-/*-------------------------------------------------
- cpu_abort_timeslice - abort execution
- for the current timeslice, allowing other
- CPUs to run before we run again
--------------------------------------------------*/
-
-void cpu_abort_timeslice(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
- int delta;
-
- /* ignore if not the executing CPU */
- if (device != device->machine->cpuexec_data->executingcpu)
- return;
-
- /* swallow the remaining cycles */
- if (classdata->icount != NULL)
- {
- delta = *classdata->icount;
- classdata->cycles_stolen += delta;
- classdata->cycles_running -= delta;
- *classdata->icount -= delta;
- }
-}
-
-
-
-/***************************************************************************
- SYNCHRONIZATION HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- cpu_yield - yield the given CPU until the end
- of the current timeslice
--------------------------------------------------*/
-
-void cpu_yield(running_device *device)
-{
- /* suspend against the timeslice */
- cpu_suspend(device, SUSPEND_REASON_TIMESLICE, FALSE);
-}
-
-
-/*-------------------------------------------------
- cpu_spin - burn CPU cycles until our timeslice
- is up
--------------------------------------------------*/
-
-void cpu_spin(running_device *device)
-{
- /* suspend against the timeslice */
- cpu_suspend(device, SUSPEND_REASON_TIMESLICE, TRUE);
-}
-
-
-/*-------------------------------------------------
- cpu_spinuntil_trigger - burn specified CPU
- cycles until a timer trigger
--------------------------------------------------*/
-
-void cpu_spinuntil_trigger(running_device *device, int trigger)
-{
- /* suspend until the given trigger fires */
- suspend_until_trigger(device, trigger, TRUE);
-}
-
-
-/*-------------------------------------------------
- cpu_spinuntil_int - burn CPU cycles until the
- next interrupt
--------------------------------------------------*/
-
-void cpu_spinuntil_int(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* suspend until the given trigger fires */
- suspend_until_trigger(device, classdata->inttrigger, TRUE);
-}
-
-
-/*-------------------------------------------------
- cpu_spinuntil_time - burn CPU cycles for a
- specific period of time
--------------------------------------------------*/
-
-void cpu_spinuntil_time(running_device *device, attotime duration)
-{
- static int timetrig = 0;
-
- /* suspend until the given trigger fires */
- suspend_until_trigger(device, TRIGGER_SUSPENDTIME + timetrig, TRUE);
-
- /* then set a timer for it */
- cpuexec_triggertime(device->machine, TRIGGER_SUSPENDTIME + timetrig, duration);
- timetrig = (timetrig + 1) % 256;
-}
-
-
-
-/***************************************************************************
- TRIGGERS
-***************************************************************************/
-
-/*-------------------------------------------------
- cpuexec_trigger - generate a trigger now
--------------------------------------------------*/
-
-void cpuexec_trigger(running_machine *machine, int trigger)
-{
- running_device *cpu;
-
- /* look for suspended CPUs waiting for this trigger and unsuspend them */
- for (cpu = machine->firstcpu; cpu != NULL; cpu = cpu_next(cpu))
- {
- cpu_class_data *classdata = get_class_data(cpu);
-
- /* if we're executing, for an immediate abort */
- cpu_abort_timeslice(cpu);
-
- /* see if this is a matching trigger */
- if ((classdata->nextsuspend & SUSPEND_REASON_TRIGGER) != 0 && classdata->trigger == trigger)
- {
- cpu_resume(cpu, SUSPEND_REASON_TRIGGER);
- classdata->trigger = 0;
- }
- }
-}
-
-
-/*-------------------------------------------------
- cpuexec_triggertime - generate a trigger after a
- specific period of time
--------------------------------------------------*/
-
-void cpuexec_triggertime(running_machine *machine, int trigger, attotime duration)
-{
- timer_set(machine, duration, NULL, trigger, triggertime_callback);
-}
-
-
-/*-------------------------------------------------
- cpu_triggerint - generate a trigger
- corresponding to an interrupt on the given CPU
--------------------------------------------------*/
-
-void cpu_triggerint(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* signal this CPU's interrupt trigger */
- cpuexec_trigger(device->machine, classdata->inttrigger);
-}
-
-
-
-/***************************************************************************
- INTERRUPTS
-***************************************************************************/
-
-/*-------------------------------------------------
- cpu_set_input_line - set the logical state
- (ASSERT_LINE/CLEAR_LINE) of an input line
- on a CPU
--------------------------------------------------*/
-
-void cpu_set_input_line(running_device *device, int line, int state)
-{
- cpu_class_data *classdata = get_class_data(device);
- int vector = (line >= 0 && line < MAX_INPUT_LINES) ? classdata->input[line].vector : 0xff;
- cpu_set_input_line_and_vector(device, line, state, vector);
-}
-
-
-/*-------------------------------------------------
- cpu_set_input_line_vector - set the vector to
- be returned during a CPU's interrupt
- acknowledge cycle
--------------------------------------------------*/
-
-void cpu_set_input_line_vector(running_device *device, int line, int vector)
-{
- cpu_class_data *classdata = get_class_data(device);
- if (line >= 0 && line < MAX_INPUT_LINES)
- {
- classdata->input[line].vector = vector;
- return;
- }
- LOG(("cpu_set_input_line_vector CPU '%s' line %d > max input lines\n", device->tag(), line));
-}
-
-
-/*-------------------------------------------------
- cpu_set_input_line_and_vector - set the logical
- state (ASSERT_LINE/CLEAR_LINE) of an input
- line on a CPU and its associated vector
--------------------------------------------------*/
-
-void cpu_set_input_line_and_vector(running_device *device, int line, int state, int vector)
-{
- cpu_class_data *classdata = get_class_data(device);
-
- /* catch errors where people use PULSE_LINE for CPUs that don't support it */
- if (state == PULSE_LINE && line != INPUT_LINE_NMI && line != INPUT_LINE_RESET)
- fatalerror("CPU %s: PULSE_LINE can only be used for NMI and RESET lines\n", device->tag());
-
- if (line >= 0 && line < MAX_INPUT_LINES)
- {
- cpu_input_data *inputline = &classdata->input[line];
- INT32 input_event = (state & 0xff) | (vector << 8);
- int event_index = inputline->qindex++;
-
- LOG(("cpu_set_input_line_and_vector('%s',%d,%d,%02x)\n", device->tag(), line, state, vector));
-
- /* if we're full of events, flush the queue and log a message */
- if (event_index >= ARRAY_LENGTH(inputline->queue))
- {
- inputline->qindex--;
- empty_event_queue(device->machine, (void *)device, line);
- event_index = inputline->qindex++;
- logerror("Exceeded pending input line event queue on CPU '%s'!\n", device->tag());
- }
-
- /* enqueue the event */
- if (event_index < ARRAY_LENGTH(inputline->queue))
- {
- inputline->queue[event_index] = input_event;
-
- /* if this is the first one, set the timer */
- if (event_index == 0)
- timer_call_after_resynch(device->machine, (void *)device, line, empty_event_queue);
- }
- }
-}
-
-
-/*-------------------------------------------------
- cpu_set_irq_callback - install a driver-
- specific callback for IRQ acknowledge
--------------------------------------------------*/
-
-void cpu_set_irq_callback(running_device *device, cpu_irq_callback callback)
-{
- cpu_class_data *classdata = get_class_data(device);
- classdata->driver_irq = callback;
-}
-
-
-
-/***************************************************************************
- CHEESY FAKE VIDEO TIMING (OBSOLETE)
-***************************************************************************/
-
-/*-------------------------------------------------
- cpu_getiloops - return the cheesy VBLANK
- interrupt counter (deprecated)
--------------------------------------------------*/
-
-int cpu_getiloops(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
- return classdata->iloops;
-}
-
-
-
-/***************************************************************************
- INTERNAL FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- update_clock_information - recomputes clock
- information for the specified CPU
--------------------------------------------------*/
-
-static void update_clock_information(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
- INT64 attos;
-
- /* recompute cps and spc */
- classdata->cycles_per_second = (double)classdata->clock * classdata->clockscale;
- classdata->attoseconds_per_cycle = HZ_TO_ATTOSECONDS((double)classdata->clock * classdata->clockscale);
-
- /* update the CPU's divisor */
- attos = classdata->attoseconds_per_cycle;
- classdata->divshift = 0;
- while (attos >= (1UL << 31))
- {
- classdata->divshift++;
- attos >>= 1;
- }
- classdata->divisor = attos;
-
- /* re-compute the perfect interleave factor */
- compute_perfect_interleave(device->machine);
-}
-
-
-/*-------------------------------------------------
- compute_perfect_interleave - compute the
- "perfect" interleave interval
--------------------------------------------------*/
-
-static void compute_perfect_interleave(running_machine *machine)
-{
- running_device *firstcpu = machine->firstcpu;
- if (firstcpu != NULL)
- {
- attoseconds_t smallest = get_minimum_quantum(firstcpu);
- attoseconds_t perfect = ATTOSECONDS_PER_SECOND - 1;
- running_device *cpu;
-
- /* start with a huge time factor and find the 2nd smallest cycle time */
- for (cpu = cpu_next(firstcpu); cpu != NULL; cpu = cpu_next(cpu))
- {
- attoseconds_t curquantum = get_minimum_quantum(cpu);
-
- /* find the 2nd smallest cycle interval */
- if (curquantum < smallest)
- {
- perfect = smallest;
- smallest = curquantum;
- }
- else if (curquantum < perfect)
- perfect = curquantum;
- }
-
- /* adjust the final value */
- timer_set_minimum_quantum(machine, perfect);
-
- LOG(("Perfect interleave = %.9f, smallest = %.9f\n", ATTOSECONDS_TO_DOUBLE(perfect), ATTOSECONDS_TO_DOUBLE(smallest)));
- }
-}
-
-
-/*-------------------------------------------------
- on_vblank - calls any external callbacks
- for this screen
--------------------------------------------------*/
-
-static void on_vblank(running_device *device, void *param, int vblank_state)
-{
- /* VBLANK starting */
- if (vblank_state)
- {
- running_device *cpu;
-
- /* find any CPUs that have this screen as their VBLANK interrupt source */
- for (cpu = device->machine->firstcpu; cpu != NULL; cpu = cpu_next(cpu))
- {
- const cpu_config *config = (const cpu_config *)cpu->baseconfig().inline_config;
- cpu_class_data *classdata = get_class_data(cpu);
- int cpu_interested;
-
- /* start the interrupt counter */
- if (!(classdata->suspend & SUSPEND_REASON_DISABLE))
- classdata->iloops = 0;
- else
- classdata->iloops = -1;
-
- /* the hack style VBLANK decleration always uses the first screen */
- if (config->vblank_interrupts_per_frame > 1)
- cpu_interested = TRUE;
-
- /* for new style declaration, we need to compare the tags */
- else if (config->vblank_interrupt_screen != NULL)
- cpu_interested = (strcmp(config->vblank_interrupt_screen, device->tag()) == 0);
-
- /* no VBLANK interrupt, not interested */
- else
- cpu_interested = FALSE;
-
- /* if interested, call the interrupt handler */
- if (cpu_interested)
- {
- if (!(classdata->suspend & (SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE)))
- (*config->vblank_interrupt)(cpu);
-
- /* if we have more than one interrupt per frame, start the timer now to trigger the rest of them */
- if (config->vblank_interrupts_per_frame > 1 && !(classdata->suspend & SUSPEND_REASON_DISABLE))
- {
- classdata->partial_frame_period = attotime_div(video_screen_get_frame_period(device->machine->primary_screen), config->vblank_interrupts_per_frame);
- timer_adjust_oneshot(classdata->partial_frame_timer, classdata->partial_frame_period, 0);
- }
- }
- }
- }
-}
-
-
-/*-------------------------------------------------
- trigger_partial_frame_interrupt - called to
- trigger a partial frame interrupt
--------------------------------------------------*/
-
-static TIMER_CALLBACK( trigger_partial_frame_interrupt )
-{
- running_device *device = (running_device *)ptr;
- const cpu_config *config = (const cpu_config *)device->baseconfig().inline_config;
- cpu_class_data *classdata = get_class_data(device);
-
- if (classdata->iloops == 0)
- classdata->iloops = config->vblank_interrupts_per_frame;
-
- classdata->iloops--;
-
- /* call the interrupt handler */
- if (!cpu_is_suspended(device, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
- (*config->vblank_interrupt)(device);
-
- /* more? */
- if (classdata->iloops > 1)
- timer_adjust_oneshot(classdata->partial_frame_timer, classdata->partial_frame_period, 0);
-}
-
-
-/*-------------------------------------------------
- trigger_periodic_interrupt - timer callback for
- timed interrupts
--------------------------------------------------*/
-
-static TIMER_CALLBACK( trigger_periodic_interrupt )
-{
- running_device *device = (running_device *)ptr;
- const cpu_config *config = (const cpu_config *)device->baseconfig().inline_config;
-
- /* bail if there is no routine */
- if (config->timed_interrupt != NULL && !cpu_is_suspended(device, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
- (*config->timed_interrupt)(device);
-}
-
-
-/*-------------------------------------------------
- triggertime_callback - signal a global trigger
--------------------------------------------------*/
-
-static TIMER_CALLBACK( triggertime_callback )
-{
- cpuexec_trigger(machine, param);
-}
-
-
-/*-------------------------------------------------
- empty_event_queue - empty a CPU's event queue
- for a specific input line
--------------------------------------------------*/
-
-static TIMER_CALLBACK( empty_event_queue )
-{
- running_device *device = (running_device *)ptr;
- cpu_class_data *classdata = get_class_data(device);
- cpu_input_data *inputline = &classdata->input[param];
- int curevent;
-
- /* loop over all events */
- for (curevent = 0; curevent < inputline->qindex; curevent++)
- {
- INT32 input_event = inputline->queue[curevent];
- int state = input_event & 0xff;
- int vector = input_event >> 8;
-
- /* set the input line state and vector */
- inputline->curstate = state;
- inputline->curvector = vector;
-
- /* special case: RESET */
- if (param == INPUT_LINE_RESET)
- {
- /* if we're asserting the line, just halt the CPU */
- if (state == ASSERT_LINE)
- cpu_suspend(device, SUSPEND_REASON_RESET, 1);
- else
- {
- /* if we're clearing the line that was previously asserted, or if we're just */
- /* pulsing the line, reset the CPU */
- if ((state == CLEAR_LINE && cpu_is_suspended(device, SUSPEND_REASON_RESET)) || state == PULSE_LINE)
- device->reset();
-
- /* if we're clearing the line, make sure the CPU is not halted */
- cpu_resume(device, SUSPEND_REASON_RESET);
- }
- }
-
- /* special case: HALT */
- else if (param == INPUT_LINE_HALT)
- {
- /* if asserting, halt the CPU */
- if (state == ASSERT_LINE)
- cpu_suspend(device, SUSPEND_REASON_HALT, 1);
-
- /* if clearing, unhalt the CPU */
- else if (state == CLEAR_LINE)
- cpu_resume(device, SUSPEND_REASON_HALT);
- }
-
- /* all other cases */
- else
- {
- /* switch off the requested state */
- switch (state)
- {
- case PULSE_LINE:
- cpu_set_info(device, CPUINFO_INT_INPUT_STATE + param, ASSERT_LINE);
- cpu_set_info(device, CPUINFO_INT_INPUT_STATE + param, CLEAR_LINE);
- break;
-
- case HOLD_LINE:
- case ASSERT_LINE:
- cpu_set_info(device, CPUINFO_INT_INPUT_STATE + param, ASSERT_LINE);
- break;
-
- case CLEAR_LINE:
- cpu_set_info(device, CPUINFO_INT_INPUT_STATE + param, CLEAR_LINE);
- break;
-
- default:
- logerror("empty_event_queue cpu '%s', line %d, unknown state %d\n", device->tag(), param, state);
- break;
- }
-
- /* generate a trigger to unsuspend any CPUs waiting on the interrupt */
- if (state != CLEAR_LINE)
- cpu_triggerint(device);
- }
- }
-
- /* reset counter */
- inputline->qindex = 0;
-}
-
-
-/*-------------------------------------------------
- standard_irq_callback - IRQ acknowledge
- callback; handles HOLD_LINE case and signals
- to the debugger
--------------------------------------------------*/
-
-static IRQ_CALLBACK( standard_irq_callback )
-{
- cpu_class_data *classdata = get_class_data(device);
- cpu_input_data *inputline = &classdata->input[irqline];
- int vector = inputline->curvector;
-
- LOG(("standard_irq_callback('%s', %d) $%04x\n", device->tag(), irqline, vector));
-
- /* if the IRQ state is HOLD_LINE, clear it */
- if (inputline->curstate == HOLD_LINE)
- {
- LOG(("->set_irq_line('%s',%d,%d)\n", device->tag(), irqline, CLEAR_LINE));
- cpu_set_info(device, CPUINFO_INT_INPUT_STATE + irqline, CLEAR_LINE);
- inputline->curstate = CLEAR_LINE;
- }
-
- /* if there's a driver callback, run it */
- if (classdata->driver_irq != NULL)
- vector = (*classdata->driver_irq)(device, irqline);
-
- /* notify the debugger */
- debugger_interrupt_hook(device, irqline);
-
- /* otherwise, just return the current vector */
- return vector;
-}
-
-
-/*-------------------------------------------------
- register_save_states - register for CPU-
- specific save states
--------------------------------------------------*/
-
-static void register_save_states(running_device *device)
-{
- cpu_class_data *classdata = get_class_data(device);
- int line;
-
- state_save_register_device_item(device, 0, classdata->suspend);
- state_save_register_device_item(device, 0, classdata->nextsuspend);
- state_save_register_device_item(device, 0, classdata->eatcycles);
- state_save_register_device_item(device, 0, classdata->nexteatcycles);
- state_save_register_device_item(device, 0, classdata->trigger);
-
- state_save_register_device_item(device, 0, classdata->iloops);
-
- state_save_register_device_item(device, 0, classdata->totalcycles);
- state_save_register_device_item(device, 0, classdata->localtime.seconds);
- state_save_register_device_item(device, 0, classdata->localtime.attoseconds);
- state_save_register_device_item(device, 0, classdata->clock);
- state_save_register_device_item(device, 0, classdata->clockscale);
-
- for (line = 0; line < ARRAY_LENGTH(classdata->input); line++)
- {
- cpu_input_data *inputline = &classdata->input[line];
- state_save_register_device_item(device, line, inputline->vector);
- state_save_register_device_item(device, line, inputline->curvector);
- state_save_register_device_item(device, line, inputline->curstate);
- }
-}
-
-
-/*-------------------------------------------------
- rebuild_execute_list - rebuild the list of
- executing CPUs, moving suspended CPUs to the
- end
--------------------------------------------------*/
-
-static void rebuild_execute_list(running_machine *machine)
-{
- cpuexec_private *global = machine->cpuexec_data;
- running_device *curcpu;
- cpu_class_data **tailptr;
-
- /* start with an empty list */
- tailptr = &global->executelist;
- *tailptr = NULL;
-
- /* first iterate over non-suspended CPUs */
- for (curcpu = machine->firstcpu; curcpu != NULL; curcpu = cpu_next(curcpu))
- {
- cpu_class_data *classdata = get_class_data(curcpu);
- if (classdata->suspend == 0)
- {
- *tailptr = classdata;
- tailptr = &classdata->next;
- classdata->next = NULL;
- }
- }
-
- /* then add the suspended CPUs */
- for (curcpu = machine->firstcpu; curcpu != NULL; curcpu = cpu_next(curcpu))
- {
- cpu_class_data *classdata = get_class_data(curcpu);
- if (classdata->suspend != 0)
- {
- *tailptr = classdata;
- tailptr = &classdata->next;
- classdata->next = NULL;
- }
- }
-}
-
-
-/*-------------------------------------------------
- get_register_value - return a register value
- of a CPU using the state table
--------------------------------------------------*/
-
-static UINT64 get_register_value(running_device *device, void *baseptr, const cpu_state_entry *entry)
-{
- void *dataptr;
- UINT64 result;
-
- /* NULL entry returns 0 */
- if (entry == NULL || baseptr == NULL)
- return 0;
-
- /* if we have an exporter, call it now */
- if ((entry->flags & CPUSTATE_EXPORT) != 0)
- {
- cpu_state_io_func exportcb = (cpu_state_io_func)device->get_config_fct(CPUINFO_FCT_EXPORT_STATE);
- assert(exportcb != NULL);
- (*exportcb)(device, baseptr, entry);
- }
-
- /* pick up the value */
- dataptr = (UINT8 *)baseptr + entry->dataoffs;
- switch (entry->datasize)
- {
- default:
- case 1: result = *(UINT8 *)dataptr; break;
- case 2: result = *(UINT16 *)dataptr; break;
- case 4: result = *(UINT32 *)dataptr; break;
- case 8: result = *(UINT64 *)dataptr; break;
- }
- return result & entry->mask;
-}
-
-
-/*-------------------------------------------------
- set_register_value - set the value of a
- CPU register using the state table
--------------------------------------------------*/
-
-static void set_register_value(running_device *device, void *baseptr, const cpu_state_entry *entry, UINT64 value)
-{
- void *dataptr;
-
- /* NULL entry is a no-op */
- if (entry == NULL || baseptr == NULL)
- return;
-
- /* apply the mask */
- value &= entry->mask;
-
- /* sign-extend if necessary */
- if ((entry->flags & CPUSTATE_IMPORT_SEXT) != 0 && value > (entry->mask >> 1))
- value |= ~entry->mask;
-
- /* store the value */
- dataptr = (UINT8 *)baseptr + entry->dataoffs;
- switch (entry->datasize)
- {
- default:
- case 1: *(UINT8 *)dataptr = value; break;
- case 2: *(UINT16 *)dataptr = value; break;
- case 4: *(UINT32 *)dataptr = value; break;
- case 8: *(UINT64 *)dataptr = value; break;
- }
-
- /* if we have an importer, call it now */
- if ((entry->flags & CPUSTATE_IMPORT) != 0)
- {
- cpu_state_io_func importcb = (cpu_state_io_func)device->get_config_fct(CPUINFO_FCT_IMPORT_STATE);
- assert(importcb != NULL);
- (*importcb)(device, baseptr, entry);
- }
-}
-
-
-/*-------------------------------------------------
- get_register_string_value - return a string
- representation of a CPU register using the
- state table
--------------------------------------------------*/
-
-static void get_register_string_value(running_device *device, void *baseptr, const cpu_state_entry *entry, char *dest)
-{
- static const UINT64 decdivisor[] = {
- 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
- U64(10000000000), U64(100000000000), U64(1000000000000),
- U64(10000000000000), U64(100000000000000), U64(1000000000000000),
- U64(10000000000000000), U64(100000000000000000), U64(1000000000000000000),
- U64(10000000000000000000)
- };
- static const char hexchars[] = "0123456789ABCDEF";
- int leadzero = 0, width = 0, percent = 0, explicitsign = 0, hitnonzero = 0, reset;
- const char *fptr;
- UINT64 result;
-
- /* NULL entry does nothing */
- if (entry == NULL || entry->symbol == NULL || entry->format == NULL)
- return;
-
- /* fetch the data */
- result = get_register_value(device, baseptr, entry);
-
- /* start with the basics */
- dest += sprintf(dest, "%s%s:", (entry->flags & CPUSTATE_NOSHOW) ? "~" : "", entry->symbol);
-
- /* parse the format */
- reset = TRUE;
- for (fptr = entry->format; *fptr != 0; fptr++)
- {
- int digitnum;
-
- /* reset any accumulated state */
- if (reset)
- leadzero = width = percent = explicitsign = reset = 0;
-
- /* if we're not within a format, then anything other than a % outputs directly */
- if (!percent && *fptr != '%')
- {
- *dest++ = *fptr;
- continue;
- }
-
- /* handle each character in turn */
- switch (*fptr)
- {
- /* % starts a format; %% outputs a single % */
- case '%':
- if (!percent)
- percent = TRUE;
- else
- {
- *dest++ = *fptr;
- percent = FALSE;
- }
- break;
-
- /* 0 means insert leading 0s, unless it follows another width digit */
- case '0':
- if (width == 0)
- leadzero = TRUE;
- else
- width *= 10;
- break;
-
- /* 1-9 accumulate into the width */
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- width = width * 10 + (*fptr - '0');
- break;
-
- /* + means explicit sign */
- case '+':
- explicitsign = TRUE;
- break;
-
- /* X outputs as hexadecimal */
- case 'X':
- if (width == 0)
- fatalerror("Width required for %%X formats\n");
- hitnonzero = FALSE;
- while (leadzero && width > 16)
- {
- *dest++ = ' ';
- width--;
- }
- for (digitnum = 15; digitnum >= 0; digitnum--)
- {
- int digit = (result >> (4 * digitnum)) & 0x0f;
- if (digit != 0)
- *dest++ = hexchars[digit];
- else if (hitnonzero || (leadzero && digitnum < width) || digitnum == 0)
- *dest++ = '0';
- hitnonzero |= digit;
- }
- reset = TRUE;
- break;
-
- /* d outputs as signed decimal */
- case 'd':
- if (width == 0)
- fatalerror("Width required for %%d formats\n");
- if ((result & entry->mask) > (entry->mask >> 1))
- {
- result = -result & entry->mask;
- *dest++ = '-';
- width--;
- }
- else if (explicitsign)
- {
- *dest++ = '+';
- width--;
- }
- /* fall through to unsigned case */
-
- /* u outputs as unsigned decimal */
- case 'u':
- if (width == 0)
- fatalerror("Width required for %%u formats\n");
- hitnonzero = FALSE;
- while (leadzero && width > ARRAY_LENGTH(decdivisor))
- {
- *dest++ = ' ';
- width--;
- }
- for (digitnum = ARRAY_LENGTH(decdivisor) - 1; digitnum >= 0; digitnum--)
- {
- int digit = (result >= decdivisor[digitnum]) ? (result / decdivisor[digitnum]) % 10 : 0;
- if (digit != 0)
- *dest++ = '0' + digit;
- else if (hitnonzero || (leadzero && digitnum < width) || digitnum == 0)
- *dest++ = '0';
- hitnonzero |= digit;
- }
- reset = TRUE;
- break;
-
- /* s is a custom format */
- case 's':
- {
- cpu_string_io_func exportstring = (cpu_string_io_func)device->get_config_fct(CPUINFO_FCT_EXPORT_STRING);
- assert(exportstring != NULL);
- (*exportstring)(device, baseptr, entry, dest);
- dest += strlen(dest);
- break;
- }
-
- /* other formats unknown */
- default:
- fatalerror("Unknown format character '%c'\n", *fptr);
- break;
- }
- }
- *dest = 0;
-}
-
-
-/*-------------------------------------------------
- get_register_string_max_width - return the
- maximum width of a string described by a
- format
--------------------------------------------------*/
-
-#ifdef UNUSED_FUNCTION
-static int get_register_string_max_width(running_device *device, void *baseptr, const cpu_state_entry *entry)
-{
- int /*leadzero = 0,*/ width = 0, percent = 0, explicitsign = 0, reset;
- int totalwidth = 0;
- const char *fptr;
-
- /* NULL entry does nothing */
- if (entry == NULL || entry->symbol == NULL || entry->format == NULL)
- return 0;
-
- /* parse the format */
- reset = TRUE;
- for (fptr = entry->format; *fptr != 0; fptr++)
- {
- /* reset any accumulated state */
- if (reset)
- /*leadzero =*/ width = percent = explicitsign = reset = 0;
-
- /* if we're not within a format, then anything other than a % outputs directly */
- if (!percent && *fptr != '%')
- {
- totalwidth++;
- continue;
- }
-
- /* handle each character in turn */
- switch (*fptr)
- {
- /* % starts a format; %% outputs a single % */
- case '%':
- if (!percent)
- percent = TRUE;
- else
- {
- totalwidth++;
- percent = FALSE;
- }
- break;
-
- /* 0 means insert leading 0s, unless it follows another width digit */
- case '0':
- if (width == 0) {
- //leadzero = TRUE;
- }
- else
- width *= 10;
- break;
-
- /* 1-9 accumulate into the width */
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- width = width * 10 + (*fptr - '0');
- break;
-
- /* + means explicit sign */
- case '+':
- explicitsign = TRUE;
- break;
-
- /* X outputs as hexadecimal */
- /* d outputs as signed decimal */
- /* u outputs as unsigned decimal */
- /* s outputs as custom format */
- case 'X':
- case 'd':
- case 'u':
- case 's':
- totalwidth += width;
- reset = TRUE;
- break;
-
- if (width == 0)
- fatalerror("Width required for %%d formats\n");
- totalwidth += width;
- break;
-
- /* other formats unknown */
- default:
- fatalerror("Unknown format character '%c'\n", *fptr);
- break;
- }
- }
- return totalwidth;
-}
-#endif