| 1 |
/*************************************************************************** |
| 2 |
|
| 3 |
cpuint.c |
| 4 |
|
| 5 |
Core multi-CPU interrupt engine. |
| 6 |
|
| 7 |
***************************************************************************/ |
| 8 |
|
| 9 |
#include <signal.h> |
| 10 |
#include "driver.h" |
| 11 |
#include "timer.h" |
| 12 |
#include "state.h" |
| 13 |
#include "mamedbg.h" |
| 14 |
#include "hiscore.h" |
| 15 |
|
| 16 |
#if (HAS_M68000 || HAS_M68010 || HAS_M68020 || HAS_M68EC020) |
| 17 |
#include "cpu/m68000/m68000.h" |
| 18 |
#endif |
| 19 |
|
| 20 |
|
| 21 |
/************************************* |
| 22 |
* |
| 23 |
* Debug logging |
| 24 |
* |
| 25 |
*************************************/ |
| 26 |
|
| 27 |
#define VERBOSE 0 |
| 28 |
|
| 29 |
#if VERBOSE |
| 30 |
#define LOG(x) logerror x |
| 31 |
#else |
| 32 |
#define LOG(x) |
| 33 |
#endif |
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
/************************************* |
| 38 |
* |
| 39 |
* Macros to help verify active CPU |
| 40 |
* |
| 41 |
*************************************/ |
| 42 |
|
| 43 |
#define VERIFY_ACTIVECPU(retval, name) \ |
| 44 |
int activecpu = cpu_getactivecpu(); \ |
| 45 |
if (activecpu < 0) \ |
| 46 |
{ \ |
| 47 |
logerror(#name "() called with no active cpu!\n"); \ |
| 48 |
return retval; \ |
| 49 |
} |
| 50 |
|
| 51 |
#define VERIFY_ACTIVECPU_VOID(name) \ |
| 52 |
int activecpu = cpu_getactivecpu(); \ |
| 53 |
if (activecpu < 0) \ |
| 54 |
{ \ |
| 55 |
logerror(#name "() called with no active cpu!\n"); \ |
| 56 |
return; \ |
| 57 |
} |
| 58 |
|
| 59 |
|
| 60 |
|
| 61 |
/************************************* |
| 62 |
* |
| 63 |
* CPU interrupt variables |
| 64 |
* |
| 65 |
*************************************/ |
| 66 |
|
| 67 |
/* current states for each CPU */ |
| 68 |
static UINT8 interrupt_enable[MAX_CPU]; |
| 69 |
static INT32 interrupt_vector[MAX_CPU][MAX_IRQ_LINES]; |
| 70 |
|
| 71 |
/* deferred states written in callbacks */ |
| 72 |
static UINT8 irq_line_state[MAX_CPU][MAX_IRQ_LINES]; |
| 73 |
static INT32 irq_line_vector[MAX_CPU][MAX_IRQ_LINES]; |
| 74 |
|
| 75 |
|
| 76 |
|
| 77 |
/************************************* |
| 78 |
* |
| 79 |
* IRQ acknowledge callbacks |
| 80 |
* |
| 81 |
*************************************/ |
| 82 |
|
| 83 |
static int cpu_0_irq_callback(int irqline); |
| 84 |
static int cpu_1_irq_callback(int irqline); |
| 85 |
static int cpu_2_irq_callback(int irqline); |
| 86 |
static int cpu_3_irq_callback(int irqline); |
| 87 |
static int cpu_4_irq_callback(int irqline); |
| 88 |
static int cpu_5_irq_callback(int irqline); |
| 89 |
static int cpu_6_irq_callback(int irqline); |
| 90 |
static int cpu_7_irq_callback(int irqline); |
| 91 |
|
| 92 |
int (*cpu_irq_callbacks[MAX_CPU])(int) = |
| 93 |
{ |
| 94 |
cpu_0_irq_callback, |
| 95 |
cpu_1_irq_callback, |
| 96 |
cpu_2_irq_callback, |
| 97 |
cpu_3_irq_callback, |
| 98 |
cpu_4_irq_callback, |
| 99 |
cpu_5_irq_callback, |
| 100 |
cpu_6_irq_callback, |
| 101 |
cpu_7_irq_callback |
| 102 |
}; |
| 103 |
|
| 104 |
static int (*drv_irq_callbacks[MAX_CPU])(int); |
| 105 |
|
| 106 |
|
| 107 |
|
| 108 |
#if 0 |
| 109 |
#pragma mark CORE CPU |
| 110 |
#endif |
| 111 |
|
| 112 |
/************************************* |
| 113 |
* |
| 114 |
* Initialize a CPU's interrupt states |
| 115 |
* |
| 116 |
*************************************/ |
| 117 |
|
| 118 |
int cpuint_init(void) |
| 119 |
{ |
| 120 |
int cpunum; |
| 121 |
int irqline; |
| 122 |
|
| 123 |
/* loop over all CPUs */ |
| 124 |
for (cpunum = 0; cpunum < cpu_gettotalcpu(); cpunum++) |
| 125 |
{ |
| 126 |
/* reset the IRQ lines */ |
| 127 |
for (irqline = 0; irqline < MAX_IRQ_LINES; irqline++) |
| 128 |
{ |
| 129 |
irq_line_state[cpunum][irqline] = CLEAR_LINE; |
| 130 |
interrupt_vector[cpunum][irqline] = |
| 131 |
irq_line_vector[cpunum][irqline] = cpunum_default_irq_vector(cpunum); |
| 132 |
} |
| 133 |
} |
| 134 |
|
| 135 |
/* set up some stuff to save */ |
| 136 |
state_save_set_current_tag(0); |
| 137 |
state_save_register_UINT8("cpu", 0, "irq enable", interrupt_enable, cpu_gettotalcpu()); |
| 138 |
state_save_register_INT32("cpu", 0, "irq vector", &interrupt_vector[0][0],cpu_gettotalcpu() * MAX_IRQ_LINES); |
| 139 |
state_save_register_UINT8("cpu", 0, "irqline state", &irq_line_state[0][0], cpu_gettotalcpu() * MAX_IRQ_LINES); |
| 140 |
state_save_register_INT32("cpu", 0, "irqline vector", &irq_line_vector[0][0], cpu_gettotalcpu() * MAX_IRQ_LINES); |
| 141 |
|
| 142 |
return 0; |
| 143 |
} |
| 144 |
|
| 145 |
|
| 146 |
|
| 147 |
/************************************* |
| 148 |
* |
| 149 |
* Reset a CPU's interrupt states |
| 150 |
* |
| 151 |
*************************************/ |
| 152 |
|
| 153 |
void cpuint_reset_cpu(int cpunum) |
| 154 |
{ |
| 155 |
int irqline; |
| 156 |
|
| 157 |
/* start with interrupts enabled, so the generic routine will work even if */ |
| 158 |
/* the machine doesn't have an interrupt enable port */ |
| 159 |
interrupt_enable[cpunum] = 1; |
| 160 |
for (irqline = 0; irqline < MAX_IRQ_LINES; irqline++) |
| 161 |
interrupt_vector[cpunum][irqline] = cpunum_default_irq_vector(cpunum); |
| 162 |
|
| 163 |
/* reset any driver hooks into the IRQ acknowledge callbacks */ |
| 164 |
drv_irq_callbacks[cpunum] = NULL; |
| 165 |
} |
| 166 |
|
| 167 |
|
| 168 |
|
| 169 |
#if 0 |
| 170 |
#pragma mark - |
| 171 |
#pragma mark INTERRUPT HANDLING |
| 172 |
#endif |
| 173 |
|
| 174 |
/************************************* |
| 175 |
* |
| 176 |
* Set IRQ callback for drivers |
| 177 |
* |
| 178 |
*************************************/ |
| 179 |
|
| 180 |
void cpu_set_irq_callback(int cpunum, int (*callback)(int)) |
| 181 |
{ |
| 182 |
drv_irq_callbacks[cpunum] = callback; |
| 183 |
} |
| 184 |
|
| 185 |
|
| 186 |
|
| 187 |
/************************************* |
| 188 |
* |
| 189 |
* Internal IRQ callbacks |
| 190 |
* |
| 191 |
*************************************/ |
| 192 |
|
| 193 |
INLINE int cpu_irq_callback(int cpunum, int irqline) |
| 194 |
{ |
| 195 |
int vector = irq_line_vector[cpunum][irqline]; |
| 196 |
|
| 197 |
LOG(("cpu_%d_irq_callback(%d) $%04xn", cpunum, irqline, vector)); |
| 198 |
|
| 199 |
/* if the IRQ state is HOLD_LINE, clear it */ |
| 200 |
if (irq_line_state[cpunum][irqline] == HOLD_LINE) |
| 201 |
{ |
| 202 |
LOG(("->set_irq_line(%d,%d,%d)\n", cpunum, irqline, CLEAR_LINE)); |
| 203 |
activecpu_set_irq_line(irqline, INTERNAL_CLEAR_LINE); |
| 204 |
irq_line_state[cpunum][irqline] = CLEAR_LINE; |
| 205 |
} |
| 206 |
|
| 207 |
/* if there's a driver callback, run it */ |
| 208 |
if (drv_irq_callbacks[cpunum]) |
| 209 |
vector = (*drv_irq_callbacks[cpunum])(irqline); |
| 210 |
|
| 211 |
/* otherwise, just return the current vector */ |
| 212 |
return vector; |
| 213 |
} |
| 214 |
|
| 215 |
static int cpu_0_irq_callback(int irqline) { return cpu_irq_callback(0, irqline); } |
| 216 |
static int cpu_1_irq_callback(int irqline) { return cpu_irq_callback(1, irqline); } |
| 217 |
static int cpu_2_irq_callback(int irqline) { return cpu_irq_callback(2, irqline); } |
| 218 |
static int cpu_3_irq_callback(int irqline) { return cpu_irq_callback(3, irqline); } |
| 219 |
static int cpu_4_irq_callback(int irqline) { return cpu_irq_callback(4, irqline); } |
| 220 |
static int cpu_5_irq_callback(int irqline) { return cpu_irq_callback(5, irqline); } |
| 221 |
static int cpu_6_irq_callback(int irqline) { return cpu_irq_callback(6, irqline); } |
| 222 |
static int cpu_7_irq_callback(int irqline) { return cpu_irq_callback(7, irqline); } |
| 223 |
|
| 224 |
|
| 225 |
|
| 226 |
/************************************* |
| 227 |
* |
| 228 |
* Set the IRQ vector for a given |
| 229 |
* IRQ line on a CPU |
| 230 |
* |
| 231 |
*************************************/ |
| 232 |
|
| 233 |
void cpu_irq_line_vector_w(int cpunum, int irqline, int vector) |
| 234 |
{ |
| 235 |
if (cpunum < cpu_gettotalcpu() && irqline >= 0 && irqline < MAX_IRQ_LINES) |
| 236 |
{ |
| 237 |
LOG(("cpu_irq_line_vector_w(%d,%d,$%04x)\n",cpunum,irqline,vector)); |
| 238 |
interrupt_vector[cpunum][irqline] = vector; |
| 239 |
return; |
| 240 |
} |
| 241 |
LOG(("cpu_irq_line_vector_w CPU#%d irqline %d > max irq lines\n", cpunum, irqline)); |
| 242 |
} |
| 243 |
|
| 244 |
|
| 245 |
|
| 246 |
/************************************* |
| 247 |
* |
| 248 |
* Generate a IRQ interrupt |
| 249 |
* |
| 250 |
*************************************/ |
| 251 |
|
| 252 |
static void cpu_manualirqcallback(int param) |
| 253 |
{ |
| 254 |
int cpunum = param & 0x0f; |
| 255 |
int state = (param >> 4) & 0x0f; |
| 256 |
int irqline = (param >> 8) & 0x7f; |
| 257 |
int set_vector = (param >> 15) & 0x01; |
| 258 |
int vector = param >> 16; |
| 259 |
|
| 260 |
LOG(("cpu_manualirqcallback %d,%d,%d\n",cpunum,irqline,state)); |
| 261 |
|
| 262 |
/* swap to the CPU's context */ |
| 263 |
cpuintrf_push_context(cpunum); |
| 264 |
|
| 265 |
/* set the IRQ line state and vector */ |
| 266 |
if (irqline >= 0 && irqline < MAX_IRQ_LINES) |
| 267 |
{ |
| 268 |
irq_line_state[cpunum][irqline] = state; |
| 269 |
if (set_vector) |
| 270 |
irq_line_vector[cpunum][irqline] = vector; |
| 271 |
} |
| 272 |
|
| 273 |
/* switch off the requested state */ |
| 274 |
switch (state) |
| 275 |
{ |
| 276 |
case PULSE_LINE: |
| 277 |
activecpu_set_irq_line(irqline, INTERNAL_ASSERT_LINE); |
| 278 |
activecpu_set_irq_line(irqline, INTERNAL_CLEAR_LINE); |
| 279 |
break; |
| 280 |
|
| 281 |
case HOLD_LINE: |
| 282 |
case ASSERT_LINE: |
| 283 |
activecpu_set_irq_line(irqline, INTERNAL_ASSERT_LINE); |
| 284 |
break; |
| 285 |
|
| 286 |
case CLEAR_LINE: |
| 287 |
activecpu_set_irq_line(irqline, INTERNAL_CLEAR_LINE); |
| 288 |
break; |
| 289 |
|
| 290 |
default: |
| 291 |
logerror("cpu_manualirqcallback cpu #%d, line %d, unknown state %d\n", cpunum, irqline, state); |
| 292 |
} |
| 293 |
cpuintrf_pop_context(); |
| 294 |
|
| 295 |
/* generate a trigger to unsuspend any CPUs waiting on the interrupt */ |
| 296 |
if (state != CLEAR_LINE) |
| 297 |
cpu_triggerint(cpunum); |
| 298 |
} |
| 299 |
|
| 300 |
|
| 301 |
void cpu_set_irq_line(int cpunum, int irqline, int state) |
| 302 |
{ |
| 303 |
int vector = 0xff; |
| 304 |
int param; |
| 305 |
|
| 306 |
/* don't trigger interrupts on suspended CPUs */ |
| 307 |
if (cpu_getstatus(cpunum) == 0) |
| 308 |
return; |
| 309 |
|
| 310 |
/* pick the vector */ |
| 311 |
if (irqline >= 0 && irqline < MAX_IRQ_LINES) |
| 312 |
vector = interrupt_vector[cpunum][irqline]; |
| 313 |
|
| 314 |
LOG(("cpu_set_irq_line(%d,%d,%d,%02x)\n", cpunum, irqline, state, vector)); |
| 315 |
|
| 316 |
/* set a timer to go off */ |
| 317 |
param = (cpunum & 0x0f) | ((state & 0x0f) << 4) | ((irqline & 0x7f) << 8) | (1 << 15) | (vector << 16); |
| 318 |
// param = (cpunum & 0x0f) | ((state & 0x0f) << 4) | ((irqline & 0x7f) << 8); |
| 319 |
timer_set(TIME_NOW, param, cpu_manualirqcallback); |
| 320 |
} |
| 321 |
|
| 322 |
|
| 323 |
void cpu_set_irq_line_and_vector(int cpunum, int irqline, int state, int vector) |
| 324 |
{ |
| 325 |
int param; |
| 326 |
|
| 327 |
/* don't trigger interrupts on suspended CPUs */ |
| 328 |
if (cpu_getstatus(cpunum) == 0) |
| 329 |
return; |
| 330 |
|
| 331 |
LOG(("cpu_set_irq_line(%d,%d,%d,%02x)\n", cpunum, irqline, state, vector)); |
| 332 |
|
| 333 |
/* set a timer to go off */ |
| 334 |
param = (cpunum & 0x0f) | ((state & 0x0f) << 4) | ((irqline & 0x7f) << 8) | (1 << 15) | (vector << 16); |
| 335 |
timer_set(TIME_NOW, param, cpu_manualirqcallback); |
| 336 |
} |
| 337 |
|
| 338 |
|
| 339 |
|
| 340 |
#if 0 |
| 341 |
#pragma mark - |
| 342 |
#pragma mark PREFERRED INTERRUPT HANDLING |
| 343 |
#endif |
| 344 |
|
| 345 |
|
| 346 |
/************************************* |
| 347 |
* |
| 348 |
* NMI interrupt generation |
| 349 |
* |
| 350 |
*************************************/ |
| 351 |
|
| 352 |
INTERRUPT_GEN( nmi_line_pulse ) |
| 353 |
{ |
| 354 |
int cpunum = cpu_getactivecpu(); |
| 355 |
if (interrupt_enable[cpunum]) |
| 356 |
cpu_set_irq_line(cpunum, IRQ_LINE_NMI, PULSE_LINE); |
| 357 |
} |
| 358 |
|
| 359 |
INTERRUPT_GEN( nmi_line_assert ) |
| 360 |
{ |
| 361 |
int cpunum = cpu_getactivecpu(); |
| 362 |
if (interrupt_enable[cpunum]) |
| 363 |
cpu_set_irq_line(cpunum, IRQ_LINE_NMI, ASSERT_LINE); |
| 364 |
} |
| 365 |
|
| 366 |
|
| 367 |
|
| 368 |
/************************************* |
| 369 |
* |
| 370 |
* IRQ n interrupt generation |
| 371 |
* |
| 372 |
*************************************/ |
| 373 |
|
| 374 |
INLINE void irqn_line_hold(int irqline) |
| 375 |
{ |
| 376 |
int cpunum = cpu_getactivecpu(); |
| 377 |
if (interrupt_enable[cpunum]) |
| 378 |
{ |
| 379 |
int vector = (irqline >= 0 && irqline < MAX_IRQ_LINES) ? interrupt_vector[cpunum][irqline] : 0xff; |
| 380 |
cpu_set_irq_line_and_vector(cpunum, irqline, HOLD_LINE, vector); |
| 381 |
} |
| 382 |
} |
| 383 |
|
| 384 |
INLINE void irqn_line_pulse(int irqline) |
| 385 |
{ |
| 386 |
int cpunum = cpu_getactivecpu(); |
| 387 |
if (interrupt_enable[cpunum]) |
| 388 |
{ |
| 389 |
int vector = (irqline >= 0 && irqline < MAX_IRQ_LINES) ? interrupt_vector[cpunum][irqline] : 0xff; |
| 390 |
cpu_set_irq_line_and_vector(cpunum, irqline, PULSE_LINE, vector); |
| 391 |
} |
| 392 |
} |
| 393 |
|
| 394 |
INLINE void irqn_line_assert(int irqline) |
| 395 |
{ |
| 396 |
int cpunum = cpu_getactivecpu(); |
| 397 |
if (interrupt_enable[cpunum]) |
| 398 |
{ |
| 399 |
int vector = (irqline >= 0 && irqline < MAX_IRQ_LINES) ? interrupt_vector[cpunum][irqline] : 0xff; |
| 400 |
cpu_set_irq_line_and_vector(cpunum, irqline, ASSERT_LINE, vector); |
| 401 |
} |
| 402 |
} |
| 403 |
|
| 404 |
|
| 405 |
|
| 406 |
/************************************* |
| 407 |
* |
| 408 |
* IRQ interrupt generation |
| 409 |
* |
| 410 |
*************************************/ |
| 411 |
|
| 412 |
INTERRUPT_GEN( irq0_line_hold ) { irqn_line_hold(0); } |
| 413 |
INTERRUPT_GEN( irq0_line_pulse ) { irqn_line_pulse(0); } |
| 414 |
INTERRUPT_GEN( irq0_line_assert ) { irqn_line_assert(0); } |
| 415 |
|
| 416 |
INTERRUPT_GEN( irq1_line_hold ) { irqn_line_hold(1); } |
| 417 |
INTERRUPT_GEN( irq1_line_pulse ) { irqn_line_pulse(1); } |
| 418 |
INTERRUPT_GEN( irq1_line_assert ) { irqn_line_assert(1); } |
| 419 |
|
| 420 |
INTERRUPT_GEN( irq2_line_hold ) { irqn_line_hold(2); } |
| 421 |
INTERRUPT_GEN( irq2_line_pulse ) { irqn_line_pulse(2); } |
| 422 |
INTERRUPT_GEN( irq2_line_assert ) { irqn_line_assert(2); } |
| 423 |
|
| 424 |
INTERRUPT_GEN( irq3_line_hold ) { irqn_line_hold(3); } |
| 425 |
INTERRUPT_GEN( irq3_line_pulse ) { irqn_line_pulse(3); } |
| 426 |
INTERRUPT_GEN( irq3_line_assert ) { irqn_line_assert(3); } |
| 427 |
|
| 428 |
INTERRUPT_GEN( irq4_line_hold ) { irqn_line_hold(4); } |
| 429 |
INTERRUPT_GEN( irq4_line_pulse ) { irqn_line_pulse(4); } |
| 430 |
INTERRUPT_GEN( irq4_line_assert ) { irqn_line_assert(4); } |
| 431 |
|
| 432 |
INTERRUPT_GEN( irq5_line_hold ) { irqn_line_hold(5); } |
| 433 |
INTERRUPT_GEN( irq5_line_pulse ) { irqn_line_pulse(5); } |
| 434 |
INTERRUPT_GEN( irq5_line_assert ) { irqn_line_assert(5); } |
| 435 |
|
| 436 |
INTERRUPT_GEN( irq6_line_hold ) { irqn_line_hold(6); } |
| 437 |
INTERRUPT_GEN( irq6_line_pulse ) { irqn_line_pulse(6); } |
| 438 |
INTERRUPT_GEN( irq6_line_assert ) { irqn_line_assert(6); } |
| 439 |
|
| 440 |
INTERRUPT_GEN( irq7_line_hold ) { irqn_line_hold(7); } |
| 441 |
INTERRUPT_GEN( irq7_line_pulse ) { irqn_line_pulse(7); } |
| 442 |
INTERRUPT_GEN( irq7_line_assert ) { irqn_line_assert(7); } |
| 443 |
|
| 444 |
|
| 445 |
|
| 446 |
#if 0 |
| 447 |
#pragma mark - |
| 448 |
#pragma mark OBSOLETE INTERRUPT HANDLING |
| 449 |
#endif |
| 450 |
|
| 451 |
/************************************* |
| 452 |
* |
| 453 |
* Interrupt enabling |
| 454 |
* |
| 455 |
*************************************/ |
| 456 |
|
| 457 |
static void cpu_clearintcallback(int cpunum) |
| 458 |
{ |
| 459 |
int irqcount = cputype_get_interface(Machine->drv->cpu[cpunum].cpu_type & ~CPU_FLAGS_MASK)->num_irqs; |
| 460 |
int irqline; |
| 461 |
|
| 462 |
cpuintrf_push_context(cpunum); |
| 463 |
|
| 464 |
/* clear NMI and all IRQs */ |
| 465 |
activecpu_set_irq_line(IRQ_LINE_NMI, INTERNAL_CLEAR_LINE); |
| 466 |
for (irqline = 0; irqline < irqcount; irqline++) |
| 467 |
activecpu_set_irq_line(irqline, INTERNAL_CLEAR_LINE); |
| 468 |
|
| 469 |
cpuintrf_pop_context(); |
| 470 |
} |
| 471 |
|
| 472 |
|
| 473 |
void cpu_interrupt_enable(int cpunum,int enabled) |
| 474 |
{ |
| 475 |
interrupt_enable[cpunum] = enabled; |
| 476 |
|
| 477 |
LOG(("CPU#%d interrupt_enable=%d\n", cpunum, enabled)); |
| 478 |
|
| 479 |
/* make sure there are no queued interrupts */ |
| 480 |
if (enabled == 0) |
| 481 |
timer_set(TIME_NOW, cpunum, cpu_clearintcallback); |
| 482 |
} |
| 483 |
|
| 484 |
|
| 485 |
WRITE_HANDLER( interrupt_enable_w ) |
| 486 |
{ |
| 487 |
VERIFY_ACTIVECPU_VOID(interrupt_enable_w); |
| 488 |
cpu_interrupt_enable(activecpu, data); |
| 489 |
} |
| 490 |
|
| 491 |
|
| 492 |
READ_HANDLER( interrupt_enable_r ) |
| 493 |
{ |
| 494 |
VERIFY_ACTIVECPU(1, interrupt_enable_r); |
| 495 |
return interrupt_enable[activecpu]; |
| 496 |
} |
| 497 |
|
| 498 |
|
| 499 |
WRITE_HANDLER( interrupt_vector_w ) |
| 500 |
{ |
| 501 |
VERIFY_ACTIVECPU_VOID(interrupt_vector_w); |
| 502 |
if (interrupt_vector[activecpu][0] != data) |
| 503 |
{ |
| 504 |
LOG(("CPU#%d interrupt_vector_w $%02x\n", activecpu, data)); |
| 505 |
interrupt_vector[activecpu][0] = data; |
| 506 |
|
| 507 |
/* make sure there are no queued interrupts */ |
| 508 |
timer_set(TIME_NOW, activecpu, cpu_clearintcallback); |
| 509 |
} |
| 510 |
} |