ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/main_beos.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 1999-10-03T14:16:25Z (25 years, 1 month ago) by cebix
Branch: cebix
CVS Tags: release-0_7-2, start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

File Contents

# Content
1 /*
2 * main_beos.cpp - Startup code for BeOS
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 <AppKit.h>
22 #include <InterfaceKit.h>
23 #include <KernelKit.h>
24 #include <StorageKit.h>
25
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <time.h>
32
33 #include "sysdeps.h"
34 #include "cpu_emulation.h"
35 #include "xpram.h"
36 #include "timer.h"
37 #include "sony.h"
38 #include "disk.h"
39 #include "cdrom.h"
40 #include "scsi.h"
41 #include "audio.h"
42 #include "video.h"
43 #include "serial.h"
44 #include "ether.h"
45 #include "clip.h"
46 #include "rom_patches.h"
47 #include "prefs.h"
48 #include "prefs_editor.h"
49 #include "sys.h"
50 #include "user_strings.h"
51 #include "version.h"
52 #include "main.h"
53
54 #include "sheep_driver.h"
55
56 #define DEBUG 0
57 #include "debug.h"
58
59
60 // Constants
61 const char APP_SIGNATURE[] = "application/x-vnd.cebix-BasiliskII";
62 const char ROM_FILE_NAME[] = "ROM";
63 const char RAM_AREA_NAME[] = "Macintosh RAM";
64 const char ROM_AREA_NAME[] = "Macintosh ROM";
65 const uint32 MSG_START = 'strt'; // Emulator start message
66 const uint32 ROM_AREA_SIZE = 0x500000; // Enough to hold PowerMac ROM (for powerrom_cpu)
67
68 // Prototypes
69 #if __POWERPC__
70 static void sigsegv_handler(vregs *r);
71 #endif
72
73
74 // Application object
75 class BasiliskII : public BApplication {
76 public:
77 BasiliskII() : BApplication(APP_SIGNATURE)
78 {
79 // Find application directory and cwd to it
80 app_info the_info;
81 GetAppInfo(&the_info);
82 BEntry the_file(&the_info.ref);
83 BEntry the_dir;
84 the_file.GetParent(&the_dir);
85 BPath the_path;
86 the_dir.GetPath(&the_path);
87 chdir(the_path.Path());
88
89 // Initialize other variables
90 rom_area = ram_area = -1;
91 xpram_thread = tick_thread = -1;
92 xpram_thread_active = true;
93 tick_thread_active = true;
94 AllowQuitting = true;
95 }
96 virtual void ReadyToRun(void);
97 virtual void MessageReceived(BMessage *msg);
98 void StartEmulator(void);
99 virtual bool QuitRequested(void);
100 virtual void Quit(void);
101
102 thread_id xpram_thread; // XPRAM watchdog
103 thread_id tick_thread; // 60Hz thread
104
105 volatile bool xpram_thread_active; // Flag for quitting the XPRAM thread
106 volatile bool tick_thread_active; // Flag for quitting the 60Hz thread
107
108 bool AllowQuitting; // Flag: Alt-Q quitting allowed
109
110 private:
111 static status_t emul_func(void *arg);
112 static status_t tick_func(void *arg);
113 static status_t xpram_func(void *arg);
114 static void sigsegv_invoc(int sig, void *arg, vregs *r);
115
116 void init_rom(void);
117 void load_rom(void);
118
119 area_id rom_area; // ROM area ID
120 area_id ram_area; // RAM area ID
121
122 struct sigaction sigsegv_action; // Data access exception signal (of emulator thread)
123
124 // Exceptions
125 class area_error {};
126 class file_open_error {};
127 class file_read_error {};
128 class rom_size_error {};
129 };
130
131 static BasiliskII *the_app;
132
133
134 // CPU and FPU type, addressing mode
135 int CPUType;
136 bool CPUIs68060;
137 int FPUType;
138 bool TwentyFourBitAddressing;
139
140
141 // Global variables for PowerROM CPU
142 thread_id emul_thread = -1; // Emulator thread
143
144 #if __POWERPC__
145 int sheep_fd = -1; // fd of sheep driver
146 #endif
147
148
149 /*
150 * Create application object and start it
151 */
152
153 int main(int argc, char **argv)
154 {
155 the_app = new BasiliskII();
156 the_app->Run();
157 delete the_app;
158 return 0;
159 }
160
161
162 /*
163 * Run application
164 */
165
166 void BasiliskII::ReadyToRun(void)
167 {
168 // Initialize variables
169 RAMBaseHost = NULL;
170 ROMBaseHost = NULL;
171 srand(real_time_clock());
172 tzset();
173
174 // Print some info
175 printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
176 printf(" %s\n", GetString(STR_ABOUT_TEXT2));
177
178 // Delete old areas
179 area_id old_ram_area = find_area(RAM_AREA_NAME);
180 if (old_ram_area > 0)
181 delete_area(old_ram_area);
182 area_id old_rom_area = find_area(ROM_AREA_NAME);
183 if (old_rom_area > 0)
184 delete_area(old_rom_area);
185
186 // Read preferences
187 PrefsInit();
188
189 // Init system routines
190 SysInit();
191
192 // Show preferences editor (or start emulator directly)
193 if (!PrefsFindBool("nogui"))
194 PrefsEditor();
195 else
196 PostMessage(MSG_START);
197 }
198
199
200 /*
201 * Message received
202 */
203
204 void BasiliskII::MessageReceived(BMessage *msg)
205 {
206 switch (msg->what) {
207 case MSG_START:
208 StartEmulator();
209 break;
210 default:
211 BApplication::MessageReceived(msg);
212 }
213 }
214
215
216 /*
217 * Start emulator
218 */
219
220 void BasiliskII::StartEmulator(void)
221 {
222 char str[256];
223
224 #if REAL_ADDRESSING
225 // Open memory mess driver and remap low memory
226 sheep_fd = open("/dev/sheep", 0);
227 if (sheep_fd < 0) {
228 sprintf(str, GetString(STR_NO_SHEEP_DRIVER_ERR), strerror(sheep_fd), sheep_fd);
229 ErrorAlert(str);
230 PostMessage(B_QUIT_REQUESTED);
231 return;
232 }
233 status_t res = ioctl(sheep_fd, SHEEP_UP);
234 if (res < 0) {
235 sprintf(str, GetString(STR_SHEEP_UP_ERR), strerror(res), res);
236 ErrorAlert(str);
237 PostMessage(B_QUIT_REQUESTED);
238 return;
239 }
240 #endif
241
242 // Create area for Mac RAM
243 RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
244 if (RAMSize < 1024*1024) {
245 WarningAlert(GetString(STR_SMALL_RAM_WARN));
246 RAMSize = 1024*1024;
247 }
248
249 RAMBaseHost = (uint8 *)0x10000000;
250 ram_area = create_area(RAM_AREA_NAME, (void **)&RAMBaseHost, B_BASE_ADDRESS, RAMSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
251 if (ram_area < 0) {
252 ErrorAlert(GetString(STR_NO_RAM_AREA_ERR));
253 PostMessage(B_QUIT_REQUESTED);
254 return;
255 }
256 D(bug("RAM area %ld at %p\n", ram_area, RAMBaseHost));
257
258 // Create area and load Mac ROM
259 try {
260 init_rom();
261 } catch (area_error) {
262 ErrorAlert(GetString(STR_NO_ROM_AREA_ERR));
263 PostMessage(B_QUIT_REQUESTED);
264 return;
265 } catch (file_open_error) {
266 ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
267 PostMessage(B_QUIT_REQUESTED);
268 return;
269 } catch (file_read_error) {
270 ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
271 PostMessage(B_QUIT_REQUESTED);
272 return;
273 } catch (rom_size_error) {
274 ErrorAlert(GetString(STR_ROM_SIZE_ERR));
275 PostMessage(B_QUIT_REQUESTED);
276 return;
277 }
278
279 // Check ROM version
280 if (!CheckROM()) {
281 ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR));
282 PostMessage(B_QUIT_REQUESTED);
283 return;
284 }
285
286 // Set CPU and FPU type (UAE emulation)
287 switch (ROMVersion) {
288 case ROM_VERSION_64K:
289 case ROM_VERSION_PLUS:
290 case ROM_VERSION_CLASSIC:
291 CPUType = 0;
292 FPUType = 0;
293 TwentyFourBitAddressing = true;
294 break;
295 case ROM_VERSION_II:
296 CPUType = 2;
297 FPUType = PrefsFindBool("fpu") ? 1 : 0;
298 TwentyFourBitAddressing = true;
299 break;
300 case ROM_VERSION_32:
301 CPUType = 3;
302 FPUType = PrefsFindBool("fpu") ? 1 : 0;
303 TwentyFourBitAddressing = false;
304 break;
305 }
306 CPUIs68060 = false;
307
308 // Load XPRAM
309 XPRAMInit();
310
311 // Set boot volume
312 int16 i16 = PrefsFindInt16("bootdrive");
313 XPRAM[0x78] = i16 >> 8;
314 XPRAM[0x79] = i16 & 0xff;
315 i16 = PrefsFindInt16("bootdriver");
316 XPRAM[0x7a] = i16 >> 8;
317 XPRAM[0x7b] = i16 & 0xff;
318
319 // Start XPRAM watchdog thread
320 xpram_thread = spawn_thread(xpram_func, "XPRAM Watchdog", B_LOW_PRIORITY, this);
321 resume_thread(xpram_thread);
322
323 // Init drivers
324 SonyInit();
325 DiskInit();
326 CDROMInit();
327 SCSIInit();
328
329 // Init network
330 EtherInit();
331
332 // Init serial ports
333 SerialInit();
334
335 // Init Time Manager
336 TimerInit();
337
338 // Init clipboard
339 ClipInit();
340
341 // Init audio
342 AudioInit();
343
344 // Init video
345 if (!VideoInit(ROMVersion == ROM_VERSION_64K || ROMVersion == ROM_VERSION_PLUS || ROMVersion == ROM_VERSION_CLASSIC)) {
346 PostMessage(B_QUIT_REQUESTED);
347 return;
348 }
349
350 // Init 680x0 emulation (this also activates the memory system which is needed for PatchROM())
351 if (!Init680x0()) {
352 PostMessage(B_QUIT_REQUESTED);
353 return;
354 }
355
356 // Install ROM patches
357 if (!PatchROM()) {
358 ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR));
359 PostMessage(B_QUIT_REQUESTED);
360 return;
361 }
362
363 // Write protect ROM
364 set_area_protection(rom_area, B_READ_AREA);
365
366 // Disallow quitting with Alt-Q from now on
367 AllowQuitting = false;
368
369 // Start 60Hz interrupt
370 tick_thread = spawn_thread(tick_func, "60Hz", B_REAL_TIME_PRIORITY, this);
371 resume_thread(tick_thread);
372
373 // Start emulator thread
374 emul_thread = spawn_thread(emul_func, "MacOS", B_NORMAL_PRIORITY, this);
375 resume_thread(emul_thread);
376 }
377
378
379 /*
380 * Quit emulator
381 */
382
383 void QuitEmulator(void)
384 {
385 the_app->AllowQuitting = true;
386 be_app->PostMessage(B_QUIT_REQUESTED);
387 exit_thread(0);
388 }
389
390 bool BasiliskII::QuitRequested(void)
391 {
392 if (AllowQuitting)
393 return BApplication::QuitRequested();
394 else
395 return false;
396 }
397
398 void BasiliskII::Quit(void)
399 {
400 status_t l;
401
402 // Stop 60Hz interrupt
403 if (tick_thread > 0) {
404 tick_thread_active = false;
405 wait_for_thread(tick_thread, &l);
406 }
407
408 // Wait for emulator thread to finish
409 if (emul_thread > 0)
410 wait_for_thread(emul_thread, &l);
411
412 // Exit 680x0 emulation
413 Exit680x0();
414
415 // Stop XPRAM watchdog thread
416 if (xpram_thread > 0) {
417 xpram_thread_active = false;
418 suspend_thread(xpram_thread); // Wake thread up from snooze()
419 snooze(1000);
420 resume_thread(xpram_thread);
421 wait_for_thread(xpram_thread, &l);
422 }
423
424 // Save XPRAM
425 XPRAMExit();
426
427 // Exit video
428 VideoExit();
429
430 // Exit audio
431 AudioExit();
432
433 // Exit clipboard
434 ClipExit();
435
436 // Exit Time Manager
437 TimerExit();
438
439 // Exit serial ports
440 SerialExit();
441
442 // Exit network
443 EtherExit();
444
445 // Exit drivers
446 SCSIExit();
447 CDROMExit();
448 DiskExit();
449 SonyExit();
450
451 // Delete ROM area
452 if (rom_area >= 0)
453 delete_area(rom_area);
454
455 // Delete RAM area
456 if (ram_area >= 0)
457 delete_area(ram_area);
458
459 #if REAL_ADDRESSING
460 // Unmap low memory and close memory mess driver
461 if (sheep_fd >= 0) {
462 ioctl(sheep_fd, SHEEP_DOWN);
463 close(sheep_fd);
464 }
465 #endif
466
467 // Exit system routines
468 SysExit();
469
470 // Exit preferences
471 PrefsExit();
472
473 BApplication::Quit();
474 }
475
476
477 /*
478 * Create area for ROM (sets rom_area) and load ROM file
479 *
480 * area_error : Cannot create area
481 * file_open_error: Cannot open ROM file
482 * file_read_error: Cannot read ROM file
483 */
484
485 void BasiliskII::init_rom(void)
486 {
487 // Create area for ROM
488 ROMBaseHost = (uint8 *)0x40800000;
489 rom_area = create_area(ROM_AREA_NAME, (void **)&ROMBaseHost, B_BASE_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
490 if (rom_area < 0)
491 throw area_error();
492 D(bug("ROM area %ld at %p\n", rom_area, ROMBaseHost));
493
494 // Load ROM
495 load_rom();
496 }
497
498
499 /*
500 * Load ROM file
501 *
502 * file_open_error: Cannot open ROM file
503 * file_read_error: Cannot read ROM file
504 */
505
506 void BasiliskII::load_rom(void)
507 {
508 // Get rom file path from preferences
509 const char *rom_path = PrefsFindString("rom");
510
511 // Try to open ROM file
512 BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY);
513 if (file.InitCheck() != B_NO_ERROR)
514 throw file_open_error();
515
516 printf(GetString(STR_READING_ROM_FILE));
517
518 // Is the ROM size correct?
519 off_t rom_size = 0;
520 file.GetSize(&rom_size);
521 if (rom_size != 64*1024 && rom_size != 128*1024 && rom_size != 256*1024 && rom_size != 512*1024 && rom_size != 1024*1024)
522 throw rom_size_error();
523
524 uint8 *rom = new uint8[rom_size]; // Reading directly into the area doesn't work
525 ssize_t actual = file.Read((void *)rom, rom_size);
526 if (actual == rom_size)
527 memcpy(ROMBaseHost, rom, rom_size);
528 delete[] rom;
529 if (actual != rom_size)
530 throw file_read_error();
531 ROMSize = rom_size;
532 }
533
534
535 /*
536 * Emulator thread function
537 */
538
539 status_t BasiliskII::emul_func(void *arg)
540 {
541 BasiliskII *obj = (BasiliskII *)arg;
542
543 #if __POWERPC__
544 // Install data access signal handler
545 sigemptyset(&obj->sigsegv_action.sa_mask);
546 obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc);
547 obj->sigsegv_action.sa_flags = 0;
548 obj->sigsegv_action.sa_userdata = arg;
549 sigaction(SIGSEGV, &obj->sigsegv_action, NULL);
550 #endif
551
552 // Exceptions will send signals
553 disable_debugger(true);
554
555 // Start 68k and jump to ROM boot routine
556 Start680x0();
557
558 // Quit program
559 obj->AllowQuitting = true;
560 be_app->PostMessage(B_QUIT_REQUESTED);
561 return 0;
562 }
563
564
565 /*
566 * Code was patched, flush caches if neccessary (i.e. when using a real 680x0
567 * or a dynamically recompiling emulator)
568 */
569
570 void FlushCodeCache(void *start, uint32 size)
571 {
572 }
573
574
575 /*
576 * Interrupt flags (must be handled atomically!)
577 */
578
579 uint32 InterruptFlags = 0;
580
581 void SetInterruptFlag(uint32 flag)
582 {
583 atomic_or((int32 *)&InterruptFlags, flag);
584 }
585
586 void ClearInterruptFlag(uint32 flag)
587 {
588 atomic_and((int32 *)&InterruptFlags, ~flag);
589 }
590
591
592 /*
593 * 60Hz thread (really 60.15Hz)
594 */
595
596 status_t BasiliskII::tick_func(void *arg)
597 {
598 BasiliskII *obj = (BasiliskII *)arg;
599 int tick_counter = 0;
600 bigtime_t current = system_time();
601
602 while (obj->tick_thread_active) {
603
604 // Wait
605 current += 16625;
606 snooze_until(current, B_SYSTEM_TIMEBASE);
607
608 // Pseudo Mac 1Hz interrupt, update local time
609 if (++tick_counter > 60) {
610 tick_counter = 0;
611 WriteMacInt32(0x20c, TimerDateTime());
612 }
613
614 // Trigger 60Hz interrupt
615 SetInterruptFlag(INTFLAG_60HZ);
616 TriggerInterrupt();
617 }
618 return 0;
619 }
620
621
622 /*
623 * XPRAM watchdog thread (saves XPRAM every minute)
624 */
625
626 status_t BasiliskII::xpram_func(void *arg)
627 {
628 uint8 last_xpram[256];
629 memcpy(last_xpram, XPRAM, 256);
630
631 while (((BasiliskII *)arg)->xpram_thread_active) {
632 snooze(60*1000000);
633 if (memcmp(last_xpram, XPRAM, 256)) {
634 memcpy(last_xpram, XPRAM, 256);
635 SaveXPRAM();
636 }
637 }
638 return 0;
639 }
640
641
642 /*
643 * Display error alert
644 */
645
646 void ErrorAlert(const char *text)
647 {
648 if (PrefsFindBool("nogui")) {
649 printf(GetString(STR_SHELL_ERROR_PREFIX), text);
650 return;
651 }
652 VideoQuitFullScreen();
653 char str[256];
654 sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
655 BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
656 alert->Go();
657 }
658
659
660 /*
661 * Display warning alert
662 */
663
664 void WarningAlert(const char *text)
665 {
666 if (PrefsFindBool("nogui")) {
667 printf(GetString(STR_SHELL_WARNING_PREFIX), text);
668 return;
669 }
670 char str[256];
671 sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
672 BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
673 alert->Go();
674 }
675
676
677 /*
678 * Display choice alert
679 */
680
681 bool ChoiceAlert(const char *text, const char *pos, const char *neg)
682 {
683 char str[256];
684 sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
685 BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
686 return alert->Go() == 0;
687 }
688
689
690 /*
691 * SEGV handler
692 */
693
694 #if __POWERPC__
695 static uint32 segv_r[32];
696
697 asm void BasiliskII::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
698 {
699 mflr r0
700 stw r0,8(r1)
701 stwu r1,-56(r1)
702
703 lwz r3,segv_r(r2)
704 stmw r13,13*4(r3)
705
706 mr r3,r5
707 bl sigsegv_handler
708
709 lwz r3,segv_r(r2)
710 lmw r13,13*4(r3)
711
712 lwz r0,56+8(r1)
713 mtlr r0
714 addi r1,r1,56
715 blr
716 }
717
718 static void sigsegv_handler(vregs *r)
719 {
720 // Fetch volatile registers
721 segv_r[0] = r->r0;
722 segv_r[1] = r->r1;
723 segv_r[2] = r->r2;
724 segv_r[3] = r->r3;
725 segv_r[4] = r->r4;
726 segv_r[5] = r->r5;
727 segv_r[6] = r->r6;
728 segv_r[7] = r->r7;
729 segv_r[8] = r->r8;
730 segv_r[9] = r->r9;
731 segv_r[10] = r->r10;
732 segv_r[11] = r->r11;
733 segv_r[12] = r->r12;
734
735 // Get opcode and divide into fields
736 uint32 opcode = *(uint32 *)r->pc;
737 uint32 primop = opcode >> 26;
738 uint32 exop = (opcode >> 1) & 0x3ff;
739 uint32 ra = (opcode >> 16) & 0x1f;
740 uint32 rb = (opcode >> 11) & 0x1f;
741 uint32 rd = (opcode >> 21) & 0x1f;
742 uint32 imm = opcode & 0xffff;
743
744 // Analyze opcode
745 enum {
746 TYPE_UNKNOWN,
747 TYPE_LOAD,
748 TYPE_STORE
749 } transfer_type = TYPE_UNKNOWN;
750 enum {
751 SIZE_UNKNOWN,
752 SIZE_BYTE,
753 SIZE_HALFWORD,
754 SIZE_WORD
755 } transfer_size = SIZE_UNKNOWN;
756 enum {
757 MODE_UNKNOWN,
758 MODE_NORM,
759 MODE_U,
760 MODE_X,
761 MODE_UX
762 } addr_mode = MODE_UNKNOWN;
763 switch (primop) {
764 case 31:
765 switch (exop) {
766 case 23: // lwzx
767 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
768 case 55: // lwzux
769 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
770 case 87: // lbzx
771 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
772 case 119: // lbzux
773 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
774 case 151: // stwx
775 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
776 case 183: // stwux
777 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
778 case 215: // stbx
779 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
780 case 247: // stbux
781 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
782 case 279: // lhzx
783 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
784 case 311: // lhzux
785 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
786 case 343: // lhax
787 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
788 case 375: // lhaux
789 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
790 case 407: // sthx
791 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
792 case 439: // sthux
793 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
794 }
795 break;
796
797 case 32: // lwz
798 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
799 case 33: // lwzu
800 transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
801 case 34: // lbz
802 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
803 case 35: // lbzu
804 transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
805 case 36: // stw
806 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
807 case 37: // stwu
808 transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
809 case 38: // stb
810 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
811 case 39: // stbu
812 transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
813 case 40: // lhz
814 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
815 case 41: // lhzu
816 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
817 case 42: // lha
818 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
819 case 43: // lhau
820 transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
821 case 44: // sth
822 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
823 case 45: // sthu
824 transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
825 }
826
827 // Calculate effective address
828 uint32 addr = 0;
829 switch (addr_mode) {
830 case MODE_X:
831 case MODE_UX:
832 if (ra == 0)
833 addr = segv_r[rb];
834 else
835 addr = segv_r[ra] + segv_r[rb];
836 break;
837 case MODE_NORM:
838 case MODE_U:
839 if (ra == 0)
840 addr = (int32)(int16)imm;
841 else
842 addr = segv_r[ra] + (int32)(int16)imm;
843 break;
844 }
845
846 // Ignore ROM writes
847 if (transfer_type == TYPE_STORE && addr >= (uint32)ROMBaseHost && addr < (uint32)ROMBaseHost + ROMSize) {
848 // D(bug("WARNING: %s write access to ROM at %p, 68k pc %p\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc));
849 if (addr_mode == MODE_U || addr_mode == MODE_UX)
850 segv_r[ra] = addr;
851 r->pc += 4;
852 goto rti;
853 }
854
855 // For all other errors, jump into debugger
856 char str[256];
857 sprintf(str, "SIGSEGV\n"
858 " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
859 " xer %08lx cr %08lx fpscr %08lx\n"
860 " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
861 " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
862 " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
863 " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
864 " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
865 " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
866 " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
867 " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
868 r->pc, r->lr, r->ctr, r->msr,
869 r->xer, r->cr, r->fpscr,
870 r->r0, r->r1, r->r2, r->r3,
871 r->r4, r->r5, r->r6, r->r7,
872 r->r8, r->r9, r->r10, r->r11,
873 r->r12, segv_r[13], segv_r[14], segv_r[15],
874 segv_r[16], segv_r[17], segv_r[18], segv_r[19],
875 segv_r[20], segv_r[21], segv_r[22], segv_r[23],
876 segv_r[24], segv_r[25], segv_r[26], segv_r[27],
877 segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
878 disable_debugger(false);
879 debugger(str);
880 QuitEmulator();
881 return;
882
883 rti:
884 // Restore volatile registers
885 r->r0 = segv_r[0];
886 r->r1 = segv_r[1];
887 r->r2 = segv_r[2];
888 r->r3 = segv_r[3];
889 r->r4 = segv_r[4];
890 r->r5 = segv_r[5];
891 r->r6 = segv_r[6];
892 r->r7 = segv_r[7];
893 r->r8 = segv_r[8];
894 r->r9 = segv_r[9];
895 r->r10 = segv_r[10];
896 r->r11 = segv_r[11];
897 r->r12 = segv_r[12];
898 }
899 #endif