ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/main_amiga.cpp
Revision: 1.9
Committed: 2000-08-20T14:08:41Z (23 years, 10 months ago) by jlachmann
Branch: MAIN
Changes since 1.8: +32 -6 lines
Log Message:
added MacsBug Support -jl-

File Contents

# Content
1 /*
2 * main_amiga.cpp - Startup code for AmigaOS
3 *
4 * Basilisk II (C) 1997-2000 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <exec/types.h>
22 #include <exec/execbase.h>
23 #include <exec/memory.h>
24 #include <exec/tasks.h>
25 #include <dos/dostags.h>
26 #include <intuition/intuition.h>
27 #include <devices/timer.h>
28 #include <devices/ahi.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/intuition.h>
32
33 #include "sysdeps.h"
34 #include "cpu_emulation.h"
35 #include "main.h"
36 #include "xpram.h"
37 #include "timer.h"
38 #include "sony.h"
39 #include "disk.h"
40 #include "cdrom.h"
41 #include "scsi.h"
42 #include "audio.h"
43 #include "video.h"
44 #include "serial.h"
45 #include "ether.h"
46 #include "clip.h"
47 #include "emul_op.h"
48 #include "rom_patches.h"
49 #include "prefs.h"
50 #include "prefs_editor.h"
51 #include "sys.h"
52 #include "user_strings.h"
53 #include "version.h"
54
55 #define DEBUG 0
56 #include "debug.h"
57
58
59 // Options for libnix
60 unsigned long __stack = 0x4000; // Stack requirement
61 int __nocommandline = 1; // Disable command line parsing
62
63
64 // Constants
65 static const char ROM_FILE_NAME[] = "ROM";
66 static const char __ver[] = "$VER: " VERSION_STRING " " __DATE__;
67 static const int SCRATCH_MEM_SIZE = 65536;
68
69
70 // RAM and ROM pointers
71 uint32 RAMBaseMac; // RAM base (Mac address space)
72 uint8 *RAMBaseHost; // RAM base (host address space)
73 uint32 RAMSize; // Size of RAM
74 uint32 ROMBaseMac; // ROM base (Mac address space)
75 uint8 *ROMBaseHost; // ROM base (host address space)
76 uint32 ROMSize; // Size of ROM
77
78 uint32 MacsBugFlags = 0xbff;
79
80
81 // CPU and FPU type, addressing mode
82 int CPUType;
83 bool CPUIs68060;
84 int FPUType;
85 bool TwentyFourBitAddressing;
86
87
88 // Global variables
89 extern ExecBase *SysBase;
90 struct Library *GfxBase = NULL;
91 struct IntuitionBase *IntuitionBase = NULL;
92 struct Library *GadToolsBase = NULL;
93 struct Library *IFFParseBase = NULL;
94 struct Library *AslBase = NULL;
95 struct Library *P96Base = NULL;
96 struct Library *CyberGfxBase = NULL;
97 struct Library *TimerBase = NULL;
98 struct Library *AHIBase = NULL;
99 struct Library *DiskBase = NULL;
100
101 struct Task *MainTask; // Our task
102 uint32 ScratchMem = NULL; // Scratch memory for Mac ROM writes
103 APTR OldTrapHandler = NULL; // Old trap handler
104 APTR OldExceptionHandler = NULL; // Old exception handler
105 BYTE IRQSig = -1; // "Interrupt" signal number
106 ULONG IRQSigMask = 0; // "Interrupt" signal mask
107
108 static struct timerequest *timereq = NULL; // IORequest for timer
109
110 static struct MsgPort *ahi_port = NULL; // Port for AHI
111 static struct AHIRequest *ahi_io = NULL; // IORequest for AHI
112
113 static struct Process *tick_proc = NULL; // 60Hz process
114 static volatile bool tick_proc_active = true; // Flag for quitting the 60Hz process
115
116 static bool stack_swapped = false; // Stack swapping
117 static StackSwapStruct stack_swap;
118
119
120 // Assembly functions
121 struct trap_regs;
122 extern "C" void AtomicAnd(uint32 *p, uint32 val);
123 extern "C" void AtomicOr(uint32 *p, uint32 val);
124 extern "C" void MoveVBR(void);
125 extern "C" void TrapHandlerAsm(void);
126 extern "C" void ExceptionHandlerAsm(void);
127 extern "C" void IllInstrHandler(trap_regs *regs);
128 extern "C" void PrivViolHandler(trap_regs *regs);
129 extern "C" void quit_emulator(void);
130 uint16 EmulatedSR; // Emulated SR (supervisor bit and interrupt mask)
131
132
133 // Prototypes
134 static void jump_to_rom(void);
135 static void tick_func(void);
136
137
138 /*
139 * Main program
140 */
141
142 int main(void)
143 {
144 // Initialize variables
145 RAMBaseHost = NULL;
146 ROMBaseHost = NULL;
147 MainTask = FindTask(NULL);
148 struct DateStamp ds;
149 DateStamp(&ds);
150 srand(ds.ds_Tick);
151
152 // Print some info
153 printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
154 printf(" %s\n", GetString(STR_ABOUT_TEXT2));
155
156 // Open libraries
157 GfxBase = OpenLibrary((UBYTE *)"graphics.library", 39);
158 if (GfxBase == NULL) {
159 printf("Cannot open graphics.library V39.\n");
160 exit(1);
161 }
162 IntuitionBase = (struct IntuitionBase *)OpenLibrary((UBYTE *)"intuition.library", 39);
163 if (IntuitionBase == NULL) {
164 printf("Cannot open intuition.library V39.\n");
165 CloseLibrary(GfxBase);
166 exit(1);
167 }
168 DiskBase = (struct Library *)OpenResource((UBYTE *)"disk.resource");
169 if (DiskBase == NULL)
170 QuitEmulator();
171 GadToolsBase = OpenLibrary((UBYTE *)"gadtools.library", 39);
172 if (GadToolsBase == NULL) {
173 ErrorAlert(GetString(STR_NO_GADTOOLS_LIB_ERR));
174 QuitEmulator();
175 }
176 IFFParseBase = OpenLibrary((UBYTE *)"iffparse.library", 39);
177 if (IFFParseBase == NULL) {
178 ErrorAlert(GetString(STR_NO_IFFPARSE_LIB_ERR));
179 QuitEmulator();
180 }
181 AslBase = OpenLibrary((UBYTE *)"asl.library", 36);
182 if (AslBase == NULL) {
183 ErrorAlert(GetString(STR_NO_ASL_LIB_ERR));
184 QuitEmulator();
185 }
186
187 // These two can fail (the respective gfx support won't be available, then)
188 P96Base = OpenLibrary((UBYTE *)"Picasso96API.library", 2);
189 CyberGfxBase = OpenLibrary((UBYTE *)"cybergraphics.library", 2);
190
191 // Read preferences
192 PrefsInit();
193
194 // Open AHI
195 ahi_port = CreateMsgPort();
196 if (ahi_port) {
197 ahi_io = (struct AHIRequest *)CreateIORequest(ahi_port, sizeof(struct AHIRequest));
198 if (ahi_io) {
199 ahi_io->ahir_Version = 2;
200 if (OpenDevice((UBYTE *)AHINAME, AHI_NO_UNIT, (struct IORequest *)ahi_io, 0) == 0) {
201 AHIBase = (struct Library *)ahi_io->ahir_Std.io_Device;
202 }
203 }
204 }
205
206 // Init system routines
207 SysInit();
208
209 // Show preferences editor
210 if (!PrefsFindBool("nogui"))
211 if (!PrefsEditor())
212 QuitEmulator();
213
214 // Check start of Chip memory (because we need access to 0x0000..0x2000)
215 if ((uint32)FindName(&SysBase->MemList, (UBYTE *)"chip memory") < 0x2000) {
216 ErrorAlert(GetString(STR_NO_PREPARE_EMUL_ERR));
217 QuitEmulator();
218 }
219
220 // Open timer.device
221 timereq = (struct timerequest *)AllocVec(sizeof(timerequest), MEMF_PUBLIC | MEMF_CLEAR);
222 if (timereq == NULL) {
223 ErrorAlert(GetString(STR_NO_MEM_ERR));
224 QuitEmulator();
225 }
226 if (OpenDevice((UBYTE *)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timereq, 0)) {
227 ErrorAlert(GetString(STR_NO_TIMER_DEV_ERR));
228 QuitEmulator();
229 }
230 TimerBase = (struct Library *)timereq->tr_node.io_Device;
231
232 // Allocate scratch memory
233 ScratchMem = (uint32)AllocMem(SCRATCH_MEM_SIZE, MEMF_PUBLIC);
234 if (ScratchMem == NULL) {
235 ErrorAlert(GetString(STR_NO_MEM_ERR));
236 QuitEmulator();
237 }
238 ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block
239
240 // Create area for Mac RAM and ROM (ROM must be higher in memory,
241 // so we allocate one big chunk and put the ROM at the top of it)
242 RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
243 if (RAMSize < 1024*1024) {
244 WarningAlert(GetString(STR_SMALL_RAM_WARN));
245 RAMSize = 1024*1024;
246 }
247 RAMBaseHost = (uint8 *)AllocVec(RAMSize + 0x100000, MEMF_PUBLIC);
248 // if (RAMBaseHost == NULL) {
249 // ErrorAlert(GetString(STR_NO_MEM_ERR));
250 // QuitEmulator();
251 // }
252 if (RAMBaseHost == NULL)
253 {
254 uint32 newRAMSize = AvailMem(MEMF_LARGEST) - 0x100000;
255 char xText[120];
256
257 sprintf(xText, GetString(STR_NOT_ENOUGH_MEM_WARN), RAMSize, newRAMSize);
258
259 if (1 != ChoiceAlert(xText, "Use", "Quit"))
260 QuitEmulator();
261
262 RAMSize = newRAMSize;
263 RAMBaseHost = (uint8 *)AllocVec(RAMSize + 0x100000, MEMF_PUBLIC);
264 if (RAMBaseHost == NULL) {
265 ErrorAlert(GetString(STR_NO_MEM_ERR));
266 QuitEmulator();
267 }
268 }
269 RAMBaseMac = (uint32)RAMBaseHost;
270 D(bug("Mac RAM starts at %08lx\n", RAMBaseHost));
271 ROMBaseHost = RAMBaseHost + RAMSize;
272 ROMBaseMac = (uint32)ROMBaseHost;
273 D(bug("Mac ROM starts at %08lx\n", ROMBaseHost));
274
275 // Get rom file path from preferences
276 const char *rom_path = PrefsFindString("rom");
277
278 // Load Mac ROM
279 BPTR rom_fh = Open(rom_path ? (char *)rom_path : (char *)ROM_FILE_NAME, MODE_OLDFILE);
280 if (rom_fh == NULL) {
281 ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
282 QuitEmulator();
283 }
284 printf(GetString(STR_READING_ROM_FILE));
285 Seek(rom_fh, 0, OFFSET_END);
286 ROMSize = Seek(rom_fh, 0, OFFSET_CURRENT);
287 if (ROMSize != 512*1024 && ROMSize != 1024*1024) {
288 ErrorAlert(GetString(STR_ROM_SIZE_ERR));
289 Close(rom_fh);
290 QuitEmulator();
291 }
292 Seek(rom_fh, 0, OFFSET_BEGINNING);
293 if (Read(rom_fh, ROMBaseHost, ROMSize) != ROMSize) {
294 ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
295 Close(rom_fh);
296 QuitEmulator();
297 }
298
299 // Set CPU and FPU type
300 UWORD attn = SysBase->AttnFlags;
301 CPUType = attn & AFF_68040 ? 4 : (attn & AFF_68030 ? 3 : 2);
302 CPUIs68060 = attn & AFF_68060;
303 FPUType = attn & AFF_68881 ? 1 : 0;
304
305 // Initialize everything
306 if (!InitAll())
307 QuitEmulator();
308
309 // Move VBR away from 0 if neccessary
310 MoveVBR();
311
312 // Install trap handler
313 EmulatedSR = 0x2700;
314 OldTrapHandler = MainTask->tc_TrapCode;
315 MainTask->tc_TrapCode = (APTR)TrapHandlerAsm;
316
317 // Allocate signal for interrupt emulation and install exception handler
318 IRQSig = AllocSignal(-1);
319 IRQSigMask = 1 << IRQSig;
320 OldExceptionHandler = MainTask->tc_ExceptCode;
321 MainTask->tc_ExceptCode = (APTR)ExceptionHandlerAsm;
322 SetExcept(SIGBREAKF_CTRL_C | IRQSigMask, SIGBREAKF_CTRL_C | IRQSigMask);
323
324 // Start 60Hz process
325 tick_proc = CreateNewProcTags(
326 NP_Entry, (ULONG)tick_func,
327 NP_Name, (ULONG)"Basilisk II 60Hz",
328 NP_Priority, 5,
329 TAG_END
330 );
331
332 // Set task priority to -1 so we don't use all processing time
333 SetTaskPri(MainTask, -1);
334
335 WriteMacInt32(MacsBugFlags, 0);
336
337 // Swap stack to Mac RAM area
338 stack_swap.stk_Lower = RAMBaseHost;
339 stack_swap.stk_Upper = (ULONG)RAMBaseHost + RAMSize;
340 stack_swap.stk_Pointer = RAMBaseHost + 0x8000;
341 StackSwap(&stack_swap);
342 stack_swapped = true;
343
344 // Jump to ROM boot routine
345 Start680x0();
346
347 QuitEmulator();
348 return 0;
349 }
350
351 void Start680x0(void)
352 {
353 typedef void (*rom_func)(void);
354 rom_func fp = (rom_func)(ROMBaseHost + 0x2a);
355 fp();
356 }
357
358
359 /*
360 * Quit emulator (__saveds because it might be called from an exception)
361 */
362
363 // Assembly entry point
364 void __saveds quit_emulator(void)
365 {
366 QuitEmulator();
367 }
368
369 void QuitEmulator(void)
370 {
371 // Stop 60Hz thread
372 if (tick_proc) {
373 SetSignal(0, SIGF_SINGLE);
374 tick_proc_active = false;
375 Wait(SIGF_SINGLE);
376 }
377
378 // Restore stack
379 if (stack_swapped) {
380 stack_swapped = false;
381 StackSwap(&stack_swap);
382 }
383
384 // Remove exception handler
385 if (IRQSig >= 0) {
386 SetExcept(0, SIGBREAKF_CTRL_C | IRQSigMask);
387 MainTask->tc_ExceptCode = OldExceptionHandler;
388 FreeSignal(IRQSig);
389 }
390
391 // Remove trap handler
392 MainTask->tc_TrapCode = OldTrapHandler;
393
394 // Deinitialize everything
395 ExitAll();
396
397 // Delete RAM/ROM area
398 if (RAMBaseHost)
399 FreeVec(RAMBaseHost);
400
401 // Delete scratch memory area
402 if (ScratchMem)
403 FreeMem((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
404
405 // Close timer.device
406 if (TimerBase)
407 CloseDevice((struct IORequest *)timereq);
408 if (timereq)
409 FreeVec(timereq);
410
411 // Exit system routines
412 SysExit();
413
414 // Close AHI
415 if (AHIBase)
416 CloseDevice((struct IORequest *)ahi_io);
417 if (ahi_io)
418 DeleteIORequest((struct IORequest *)ahi_io);
419 if (ahi_port)
420 DeleteMsgPort(ahi_port);
421
422 // Exit preferences
423 PrefsExit();
424
425 // Close libraries
426 if (CyberGfxBase)
427 CloseLibrary(CyberGfxBase);
428 if (P96Base)
429 CloseLibrary(P96Base);
430 if (AslBase)
431 CloseLibrary(AslBase);
432 if (IFFParseBase)
433 CloseLibrary(IFFParseBase);
434 if (GadToolsBase)
435 CloseLibrary(GadToolsBase);
436 if (IntuitionBase)
437 CloseLibrary((struct Library *)IntuitionBase);
438 if (GfxBase)
439 CloseLibrary(GfxBase);
440
441 exit(0);
442 }
443
444
445 /*
446 * Code was patched, flush caches if neccessary (i.e. when using a real 680x0
447 * or a dynamically recompiling emulator)
448 */
449
450 void FlushCodeCache(void *start, uint32 size)
451 {
452 CacheClearE(start, size, CACRF_ClearI | CACRF_ClearD);
453 }
454
455
456 /*
457 * Interrupt flags (must be handled atomically!)
458 */
459
460 uint32 InterruptFlags;
461
462 void SetInterruptFlag(uint32 flag)
463 {
464 AtomicOr(&InterruptFlags, flag);
465 }
466
467 void ClearInterruptFlag(uint32 flag)
468 {
469 AtomicAnd(&InterruptFlags, ~flag);
470 }
471
472 void TriggerInterrupt(void)
473 {
474 Signal(MainTask, IRQSigMask);
475 }
476
477 void TriggerNMI(void)
478 {
479 AsmTriggerNMI();
480 }
481
482
483 /*
484 * 60Hz thread
485 */
486
487 static __saveds void tick_func(void)
488 {
489 int tick_counter = 0;
490 struct MsgPort *timer_port = NULL;
491 struct timerequest *timer_io = NULL;
492 ULONG timer_mask = 0;
493
494 // Start 60Hz timer
495 timer_port = CreateMsgPort();
496 if (timer_port) {
497 timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
498 if (timer_io) {
499 if (!OpenDevice((UBYTE *)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) {
500 timer_mask = 1 << timer_port->mp_SigBit;
501 timer_io->tr_node.io_Command = TR_ADDREQUEST;
502 timer_io->tr_time.tv_secs = 0;
503 timer_io->tr_time.tv_micro = 16625;
504 SendIO((struct IORequest *)timer_io);
505 }
506 }
507 }
508
509 while (tick_proc_active) {
510
511 // Wait for timer tick
512 Wait(timer_mask);
513
514 // Restart timer
515 timer_io->tr_node.io_Command = TR_ADDREQUEST;
516 timer_io->tr_time.tv_secs = 0;
517 timer_io->tr_time.tv_micro = 16625;
518 SendIO((struct IORequest *)timer_io);
519
520 // Pseudo Mac 1Hz interrupt, update local time
521 if (++tick_counter > 60) {
522 tick_counter = 0;
523 WriteMacInt32(0x20c, TimerDateTime());
524 SetInterruptFlag(INTFLAG_1HZ);
525 TriggerInterrupt();
526 }
527
528 // Trigger 60Hz interrupt
529 SetInterruptFlag(INTFLAG_60HZ);
530 TriggerInterrupt();
531 }
532
533 // Stop timer
534 if (timer_io) {
535 if (!CheckIO((struct IORequest *)timer_io))
536 AbortIO((struct IORequest *)timer_io);
537 WaitIO((struct IORequest *)timer_io);
538 CloseDevice((struct IORequest *)timer_io);
539 DeleteIORequest(timer_io);
540 }
541 if (timer_port)
542 DeleteMsgPort(timer_port);
543
544 // Main task asked for termination, send signal
545 Forbid();
546 Signal(MainTask, SIGF_SINGLE);
547 }
548
549
550 /*
551 * Display error alert
552 */
553
554 void ErrorAlert(const char *text)
555 {
556 if (PrefsFindBool("nogui")) {
557 printf(GetString(STR_SHELL_ERROR_PREFIX), text);
558 return;
559 }
560 EasyStruct req;
561 req.es_StructSize = sizeof(EasyStruct);
562 req.es_Flags = 0;
563 req.es_Title = (UBYTE *)GetString(STR_ERROR_ALERT_TITLE);
564 req.es_TextFormat = (UBYTE *)GetString(STR_GUI_ERROR_PREFIX);
565 req.es_GadgetFormat = (UBYTE *)GetString(STR_QUIT_BUTTON);
566 EasyRequest(NULL, &req, NULL, (ULONG)text);
567 }
568
569
570 /*
571 * Display warning alert
572 */
573
574 void WarningAlert(const char *text)
575 {
576 if (PrefsFindBool("nogui")) {
577 printf(GetString(STR_SHELL_WARNING_PREFIX), text);
578 return;
579 }
580 EasyStruct req;
581 req.es_StructSize = sizeof(EasyStruct);
582 req.es_Flags = 0;
583 req.es_Title = (UBYTE *)GetString(STR_WARNING_ALERT_TITLE);
584 req.es_TextFormat = (UBYTE *)GetString(STR_GUI_WARNING_PREFIX);
585 req.es_GadgetFormat = (UBYTE *)GetString(STR_OK_BUTTON);
586 EasyRequest(NULL, &req, NULL, (ULONG)text);
587 }
588
589
590 /*
591 * Display choice alert
592 */
593
594 bool ChoiceAlert(const char *text, const char *pos, const char *neg)
595 {
596 char str[256];
597 sprintf(str, "%s|%s", pos, neg);
598 EasyStruct req;
599 req.es_StructSize = sizeof(EasyStruct);
600 req.es_Flags = 0;
601 req.es_Title = (UBYTE *)GetString(STR_WARNING_ALERT_TITLE);
602 req.es_TextFormat = (UBYTE *)GetString(STR_GUI_WARNING_PREFIX);
603 req.es_GadgetFormat = (UBYTE *)str;
604 return EasyRequest(NULL, &req, NULL, (ULONG)text);
605 }
606
607
608 /*
609 * Illegal Instruction and Privilege Violation trap handlers
610 */
611
612 struct trap_regs { // This must match the layout of M68kRegisters
613 uint32 d[8];
614 uint32 a[8];
615 uint16 sr;
616 uint32 pc;
617 };
618
619 void __saveds IllInstrHandler(trap_regs *r)
620 {
621 uint16 opcode = *(uint16 *)(r->pc);
622 if ((opcode & 0xff00) != 0x7100) {
623 printf("Illegal Instruction %04x at %08lx\n", *(uint16 *)(r->pc), r->pc);
624 printf("d0 %08lx d1 %08lx d2 %08lx d3 %08lx\n"
625 "d4 %08lx d5 %08lx d6 %08lx d7 %08lx\n"
626 "a0 %08lx a1 %08lx a2 %08lx a3 %08lx\n"
627 "a4 %08lx a5 %08lx a6 %08lx a7 %08lx\n"
628 "sr %04x\n",
629 r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7],
630 r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7],
631 r->sr);
632 QuitEmulator();
633 } else {
634 // Disable interrupts
635 uint16 sr = EmulatedSR;
636 EmulatedSR |= 0x0700;
637
638 // Call opcode routine
639 EmulOp(opcode, (M68kRegisters *)r);
640 r->pc += 2;
641
642 // Restore interrupts
643 EmulatedSR = sr;
644 if ((EmulatedSR & 0x0700) == 0 && InterruptFlags)
645 Signal(MainTask, IRQSigMask);
646 }
647 }
648
649 void __saveds PrivViolHandler(trap_regs *r)
650 {
651 printf("Privileged instruction %04x %04x at %08lx\n", *(uint16 *)(r->pc), *(uint16 *)(r->pc + 2), r->pc);
652 printf("d0 %08lx d1 %08lx d2 %08lx d3 %08lx\n"
653 "d4 %08lx d5 %08lx d6 %08lx d7 %08lx\n"
654 "a0 %08lx a1 %08lx a2 %08lx a3 %08lx\n"
655 "a4 %08lx a5 %08lx a6 %08lx a7 %08lx\n"
656 "sr %04x\n",
657 r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7],
658 r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7],
659 r->sr);
660 QuitEmulator();
661 }