1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
/***************************************************************************
cpuexec.h
Core multi-CPU execution engine.
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
***************************************************************************/
#pragma once
#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif
#ifndef __CPUEXEC_H__
#define __CPUEXEC_H__
/***************************************************************************
CONSTANTS
***************************************************************************/
/* flags for MDRV_CPU_FLAGS */
enum
{
/* set this flag to disable execution of a CPU (if one is there for documentation */
/* purposes only, for example */
CPU_DISABLE = 0x0001
};
/* suspension reasons for cpunum_suspend */
enum
{
SUSPEND_REASON_HALT = 0x0001,
SUSPEND_REASON_RESET = 0x0002,
SUSPEND_REASON_SPIN = 0x0004,
SUSPEND_REASON_TRIGGER = 0x0008,
SUSPEND_REASON_DISABLE = 0x0010,
SUSPEND_REASON_TIMESLICE= 0x0020,
SUSPEND_ANY_REASON = ~0
};
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
/* opaque definition of CPU internal and debugging info */
typedef struct _cpu_debug_data cpu_debug_data;
/* interrupt callback for VBLANK and timed interrupts */
typedef void (*cpu_interrupt_func)(const device_config *device);
/* CPU description for drivers */
typedef struct _cpu_config cpu_config;
struct _cpu_config
{
cpu_type type; /* index for the CPU type */
UINT32 flags; /* flags; see #defines below */
cpu_interrupt_func vblank_interrupt; /* for interrupts tied to VBLANK */
int vblank_interrupts_per_frame;/* usually 1 */
const char * vblank_interrupt_screen; /* the screen that causes the VBLANK interrupt */
cpu_interrupt_func timed_interrupt; /* for interrupts not tied to VBLANK */
UINT64 timed_interrupt_period; /* period for periodic interrupts */
};
/* public data at the end of the device->token */
typedef struct _cpu_class_header cpu_class_header;
struct _cpu_class_header
{
cpu_debug_data * debug; /* debugging data */
cpu_set_info_func set_info; /* this CPU's set_info function */
};
/***************************************************************************
CPU DEVICE CONFIGURATION MACROS
***************************************************************************/
#define MDRV_CPU_ADD(_tag, _type, _clock) \
MDRV_DEVICE_ADD(_tag, CPU, _clock) \
MDRV_DEVICE_CONFIG_DATAPTR(cpu_config, type, CPU_##_type)
#define MDRV_CPU_MODIFY(_tag) \
MDRV_DEVICE_MODIFY(_tag)
#define MDRV_CPU_TYPE(_type) \
MDRV_DEVICE_CONFIG_DATAPTR(cpu_config, type, CPU_##_type)
#define MDRV_CPU_CLOCK(_clock) \
MDRV_DEVICE_CLOCK(_clock)
#define MDRV_CPU_REPLACE(_tag, _type, _clock) \
MDRV_DEVICE_MODIFY(_tag) \
MDRV_DEVICE_CONFIG_DATAPTR(cpu_config, type, CPU_##_type) \
MDRV_DEVICE_CLOCK(_clock)
#define MDRV_CPU_FLAGS(_flags) \
MDRV_DEVICE_CONFIG_DATA32(cpu_config, flags, _flags)
#define MDRV_CPU_CONFIG(_config) \
MDRV_DEVICE_CONFIG(_config)
#define MDRV_CPU_PROGRAM_MAP(_map) \
MDRV_DEVICE_PROGRAM_MAP(_map)
#define MDRV_CPU_DATA_MAP(_map) \
MDRV_DEVICE_DATA_MAP(_map)
#define MDRV_CPU_IO_MAP(_map) \
MDRV_DEVICE_IO_MAP(_map)
#define MDRV_CPU_VBLANK_INT(_tag, _func) \
MDRV_DEVICE_CONFIG_DATAPTR(cpu_config, vblank_interrupt, _func) \
MDRV_DEVICE_CONFIG_DATAPTR(cpu_config, vblank_interrupt_screen, _tag) \
MDRV_DEVICE_CONFIG_DATA32(cpu_config, vblank_interrupts_per_frame, 0)
#define MDRV_CPU_PERIODIC_INT(_func, _rate) \
MDRV_DEVICE_CONFIG_DATAPTR(cpu_config, timed_interrupt, _func) \
MDRV_DEVICE_CONFIG_DATA64(cpu_config, timed_interrupt_period, UINT64_ATTOTIME_IN_HZ(_rate))
/***************************************************************************
MACROS
***************************************************************************/
#define INTERRUPT_GEN(func) void func(const device_config *device)
/* helpers for using machine/cputag instead of cpu objects */
#define cputag_get_index(mach, tag) cpu_get_index(devtag_get_device(mach, tag))
#define cputag_get_address_space(mach, tag, space) cpu_get_address_space(devtag_get_device(mach, tag), space)
#define cputag_suspend(mach, tag, reason, eat) cpu_suspend(devtag_get_device(mach, tag), reason, eat)
#define cputag_resume(mach, tag, reason) cpu_resume(devtag_get_device(mach, tag), reason)
#define cputag_is_suspended(mach, tag, reason) cpu_is_suspended(devtag_get_device(mach, tag), reason)
#define cputag_get_clock(mach, tag) cpu_get_clock(devtag_get_device(mach, tag))
#define cputag_set_clock(mach, tag, clock) cpu_set_clock(devtag_get_device(mach, tag), clock)
#define cputag_clocks_to_attotime(mach, tag, clocks) cpu_clocks_to_attotime(devtag_get_device(mach, tag), clocks)
#define cputag_attotime_to_clocks(mach, tag, duration) cpu_attotime_to_clocks(devtag_get_device(mach, tag), duration)
#define cputag_get_local_time(mach, tag) cpu_get_local_time(devtag_get_device(mach, tag))
#define cputag_get_total_cycles(mach, tag) cpu_get_total_cycles(devtag_get_device(mach, tag))
#define cputag_set_input_line(mach, tag, line, state) cpu_set_input_line(devtag_get_device(mach, tag), line, state)
#define cputag_set_input_line_and_vector(mach, tag, line, state, vec) cpu_set_input_line_and_vector(devtag_get_device(mach, tag), line, state, vec)
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
/* ----- core CPU execution ----- */
/* prepare CPUs for execution */
void cpuexec_init(running_machine *machine);
/* execute for a single timeslice */
void cpuexec_timeslice(running_machine *machine);
/* temporarily boosts the interleave factor */
void cpuexec_boost_interleave(running_machine *machine, attotime timeslice_time, attotime boost_duration);
/* ----- CPU device interface ----- */
/* device get info callback */
#define CPU DEVICE_GET_INFO_NAME(cpu)
DEVICE_GET_INFO( cpu );
/* ----- global helpers ----- */
/* abort execution for the current timeslice */
void cpuexec_abort_timeslice(running_machine *machine);
/* return a string describing which CPUs are currently executing and their PC */
const char *cpuexec_describe_context(running_machine *machine);
/* ----- CPU scheduling----- */
/* suspend the given CPU for a specific reason */
void cpu_suspend(const device_config *device, int reason, int eatcycles);
/* resume the given CPU for a specific reason */
void cpu_resume(const device_config *device, int reason);
/* return TRUE if the given CPU is within its execute function */
int cpu_is_executing(const device_config *device);
/* returns TRUE if the given CPU is suspended for any of the given reasons */
int cpu_is_suspended(const device_config *device, int reason);
/* ----- CPU clock management ----- */
/* returns the current CPU's unscaled running clock speed */
int cpu_get_clock(const device_config *device);
/* sets the current CPU's clock speed and then adjusts for scaling */
void cpu_set_clock(const device_config *device, int clock);
/* returns the current scaling factor for a CPU's clock speed */
double cpu_get_clockscale(const device_config *device);
/* sets the current scaling factor for a CPU's clock speed */
void cpu_set_clockscale(const device_config *device, double clockscale);
/* converts a number of clock ticks to an attotime */
attotime cpu_clocks_to_attotime(const device_config *device, UINT64 clocks);
/* converts a duration as attotime to CPU clock ticks */
UINT64 cpu_attotime_to_clocks(const device_config *device, attotime duration);
/* ----- CPU timing ----- */
/* returns the current local time for a CPU */
attotime cpu_get_local_time(const device_config *device);
/* returns the total number of CPU cycles for a given CPU */
UINT64 cpu_get_total_cycles(const device_config *device);
/* safely eats cycles so we don't cross a timeslice boundary */
void cpu_eat_cycles(const device_config *device, int cycles);
/* apply a +/- to the current icount */
void cpu_adjust_icount(const device_config *device, int delta);
/* abort execution for the current timeslice, allowing other CPUs to run before we run again */
void cpu_abort_timeslice(const device_config *device);
/* ----- synchronization helpers ----- */
/* yield the given CPU until the end of the current timeslice */
void cpu_yield(const device_config *device);
/* burn CPU cycles until the end of the current timeslice */
void cpu_spin(const device_config *device);
/* burn specified CPU cycles until a trigger */
void cpu_spinuntil_trigger(const device_config *device, int trigger);
/* burn CPU cycles until the next interrupt */
void cpu_spinuntil_int(const device_config *device);
/* burn CPU cycles for a specific period of time */
void cpu_spinuntil_time(const device_config *device, attotime duration);
/* ----- triggers ----- */
/* generate a global trigger now */
void cpuexec_trigger(running_machine *machine, int trigger);
/* generate a global trigger after a specific period of time */
void cpuexec_triggertime(running_machine *machine, int trigger, attotime duration);
/* generate a trigger corresponding to an interrupt on the given CPU */
void cpu_triggerint(const device_config *device);
/* ----- interrupts ----- */
/* set the logical state (ASSERT_LINE/CLEAR_LINE) of the an input line on a CPU */
void cpu_set_input_line(const device_config *cpu, int line, int state);
/* set the vector to be returned during a CPU's interrupt acknowledge cycle */
void cpu_set_input_line_vector(const device_config *cpu, int irqline, int vector);
/* set the logical state (ASSERT_LINE/CLEAR_LINE) of the an input line on a CPU and its associated vector */
void cpu_set_input_line_and_vector(const device_config *cpu, int line, int state, int vector);
/* install a driver-specific callback for IRQ acknowledge */
void cpu_set_irq_callback(const device_config *cpu, cpu_irq_callback callback);
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
cpu_get_type - return the type of the
specified CPU
-------------------------------------------------*/
INLINE cpu_type cpu_get_type(const device_config *device)
{
const cpu_config *config = (const cpu_config *)device->inline_config;
return config->type;
}
/*-------------------------------------------------
cpu_get_class_header - return a pointer to
the class header
-------------------------------------------------*/
INLINE cpu_class_header *cpu_get_class_header(const device_config *device)
{
if (device->token != NULL)
return (cpu_class_header *)((UINT8 *)device->token + device->tokenbytes) - 1;
return NULL;
}
/*-------------------------------------------------
cpu_get_debug_data - return a pointer to
the given CPU's debugger data
-------------------------------------------------*/
INLINE cpu_debug_data *cpu_get_debug_data(const device_config *device)
{
cpu_class_header *classheader = cpu_get_class_header(device);
return classheader->debug;
}
/*-------------------------------------------------
cpu_get_address_space - return a pointer to
the given CPU's address space
-------------------------------------------------*/
INLINE const address_space *cpu_get_address_space(const device_config *device, int spacenum)
{
/* it is faster to pull this from the pre-fetched data, but only after we've started */
if (device->token != NULL)
return device->space[spacenum];
return memory_find_address_space(device, spacenum);
}
#endif /* __CPUEXEC_H__ */
|