home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / AmigaOS / main_amiga.cpp < prev    next >
C/C++ Source or Header  |  1999-10-21  |  16KB  |  628 lines

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