ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/main_beos.cpp
Revision: 1.13
Committed: 2004-01-12T15:29:23Z (20 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-16, nigel-build-15
Changes since 1.12: +1 -1 lines
Log Message:
Happy New Year! :)

File Contents

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