ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/powerrom_cpu/powerrom_cpu.cpp
Revision: 1.10
Committed: 2006-04-30T21:26:21Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19
Changes since 1.9: +2 -0 lines
Log Message:
Tentative fixes to BeOS idle suspend/resume routines. Well, I have no-op'ed
them. So, if someone has BeOS and wants to give it a try, please change and
test this new code. Corner case could be a resume_thread() when emul_thread
is not suspended.

Fixlet to powerrom_cpu: call idle_resume() from TriggerInterrupt().

File Contents

# Content
1 /*
2 * powerrom_cpu.cpp - Using the 680x0 emulator in PowerMac ROMs for Basilisk II
3 *
4 * Basilisk II (C) 1997-2005 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 <unistd.h>
22 #include <signal.h>
23 #include <stdlib.h>
24
25 #include <AppKit.h>
26 #include <KernelKit.h>
27 #include <StorageKit.h>
28
29 #include "sysdeps.h"
30 #include "cpu_emulation.h"
31 #include "main.h"
32 #include "emul_op.h"
33 #include "prefs.h"
34 #include "timer.h"
35 #include "user_strings.h"
36
37 #include "sheep_driver.h"
38
39 #define DEBUG 0
40 #include "debug.h"
41
42 // Save FP regs in Execute68k()?
43 #define SAVE_FP_EXEC_68K 0
44
45
46 // Constants
47 const char ROM_FILE_NAME[] = "PowerROM";
48 const char KERNEL_AREA_NAME[] = "Macintosh Kernel Data";
49 const char DR_CACHE_AREA_NAME[] = "Macintosh DR Cache";
50
51 const uint32 ROM_BASE = 0x40800000; // Base address of ROM
52 const uint32 ROM_SIZE = 0x00400000; // Size of ROM file
53 const uint32 ROM_AREA_SIZE = 0x00500000; // Size of ROM area
54
55 const uint32 DR_CACHE_BASE = 0x69000000; // Address of DR cache
56 const uint32 DR_CACHE_SIZE = 0x80000; // Size of DR Cache
57
58 const uint32 SIG_STACK_SIZE = 8192; // Size of signal stack
59
60 // PowerPC opcodes
61 const uint32 POWERPC_NOP = 0x60000000;
62 const uint32 POWERPC_ILLEGAL = 0x00000000;
63 const uint32 POWERPC_BLR = 0x4e800020;
64 const uint32 POWERPC_BCTR = 0x4e800420;
65
66 // Extra Low Memory Globals
67 #define MODE_68K 0 // 68k emulator active
68 #define MODE_EMUL_OP 1 // Within EMUL_OP routine
69
70 #define XLM_RESET_STACK 0x2800 // Reset stack pointer
71 #define XLM_KERNEL_DATA 0x2804 // Pointer to Kernel Data
72 #define XLM_TOC 0x2808 // TOC pointer of emulator
73 #define XLM_RUN_MODE 0x2810 // Current run mode, see enum above
74 #define XLM_68K_R25 0x2814 // Contents of the 68k emulator's r25 (which contains the interrupt level), saved upon entering EMUL_OP mode, used by Execute68k() and the USR1 signal handler
75 #define XLM_IRQ_NEST 0x2818 // Interrupt disable nesting counter (>0: disabled)
76 #define XLM_PVR 0x281c // Theoretical PVR
77 #define XLM_EMUL_RETURN_PROC 0x2824 // Pointer to EMUL_RETURN routine
78 #define XLM_EXEC_RETURN_PROC 0x2828 // Pointer to EXEC_RETURN routine
79 #define XLM_EMUL_OP_PROC 0x282c // Pointer to EMUL_OP routine
80 #define XLM_EMUL_RETURN_STACK 0x2830 // Stack pointer for EMUL_RETURN
81
82
83 // RAM and ROM pointers
84 uint32 RAMBaseMac; // RAM base (Mac address space)
85 uint8 *RAMBaseHost; // RAM base (host address space)
86 uint32 RAMSize; // Size of RAM
87 uint32 ROMBaseMac; // ROM base (Mac address space)
88 uint8 *ROMBaseHost; // ROM base (host address space)
89 uint32 ROMSize; // Size of ROM
90
91
92 // Emulator Data
93 struct EmulatorData {
94 uint32 v[0x400];
95 };
96
97
98 // Kernel Data
99 struct KernelData {
100 uint32 v[0x400];
101 EmulatorData ed;
102 };
103
104
105 // Exceptions
106 class file_open_error {};
107 class file_read_error {};
108 class rom_size_error {};
109
110
111 // Global variables
112 static void *TOC; // TOC pointer
113 static uint32 PVR; // Theoretical PVR
114 static int64 CPUClockSpeed; // Processor clock speed (Hz)
115 static int64 BusClockSpeed; // Bus clock speed (Hz)
116 static system_info SysInfo; // System information
117
118 static area_id kernel_area = -1; // Kernel Data area ID
119 static KernelData *kernel_data = NULL; // Pointer to Kernel Data
120 static uint32 KernelDataAddr; // Address of Kernel Data
121 static EmulatorData *emulator_data = NULL;
122 static area_id dr_cache_area; // DR Cache area ID
123 static uint32 DRCacheAddr; // Address of DR Cache
124
125 static struct sigaction sigusr1_action; // Interrupt signal (of emulator thread)
126 static bool ReadyForSignals = false; // Flag: emul_thread ready to receive signals
127
128
129 // Prototypes
130 static void sigusr1_handler(int sig, void *arg, vregs *r);
131
132 // From main_beos.cpp
133 extern int sheep_fd; // fd of sheep driver
134 extern thread_id emul_thread; // Emulator thread
135
136
137 /*
138 * Load ROM file (upper 3MB)
139 *
140 * file_open_error: Cannot open ROM file (nor use built-in ROM)
141 * file_read_error: Cannot read ROM file
142 */
143
144 // Decode LZSS data
145 static void decode_lzss(const uint8 *src, uint8 *dest, int size)
146 {
147 char dict[0x1000];
148 int run_mask = 0, dict_idx = 0xfee;
149 for (;;) {
150 if (run_mask < 0x100) {
151 // Start new run
152 if (--size < 0)
153 break;
154 run_mask = *src++ | 0xff00;
155 }
156 bool bit = run_mask & 1;
157 run_mask >>= 1;
158 if (bit) {
159 // Verbatim copy
160 if (--size < 0)
161 break;
162 int c = *src++;
163 dict[dict_idx++] = c;
164 *dest++ = c;
165 dict_idx &= 0xfff;
166 } else {
167 // Copy from dictionary
168 if (--size < 0)
169 break;
170 int idx = *src++;
171 if (--size < 0)
172 break;
173 int cnt = *src++;
174 idx |= (cnt << 4) & 0xf00;
175 cnt = (cnt & 0x0f) + 3;
176 while (cnt--) {
177 char c = dict[idx++];
178 dict[dict_idx++] = c;
179 *dest++ = c;
180 idx &= 0xfff;
181 dict_idx &= 0xfff;
182 }
183 }
184 }
185 }
186
187 static void load_rom(void)
188 {
189 // Get rom file path from preferences
190 const char *rom_path = PrefsFindString("powerrom");
191
192 // Try to open ROM file
193 BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY);
194 if (file.InitCheck() != B_NO_ERROR) {
195
196 // Failed, then ask sheep driver for ROM
197 uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
198 ssize_t actual = read(sheep_fd, (void *)rom, ROM_SIZE);
199 if (actual == ROM_SIZE) {
200 // Copy upper 3MB
201 memcpy((void *)(ROM_BASE + 0x100000), rom + 0x100000, ROM_SIZE - 0x100000);
202 delete[] rom;
203 return;
204 } else
205 throw file_open_error();
206 }
207
208 printf(GetString(STR_READING_ROM_FILE));
209
210 // Get file size
211 off_t rom_size = 0;
212 file.GetSize(&rom_size);
213
214 uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work
215 ssize_t actual = file.Read((void *)rom, ROM_SIZE);
216 if (actual == ROM_SIZE) {
217 // Plain ROM image, copy upper 3MB
218 memcpy((void *)(ROM_BASE + 0x100000), rom + 0x100000, ROM_SIZE - 0x100000);
219 delete[] rom;
220 } else {
221 if (strncmp((char *)rom, "<CHRP-BOOT>", 11) == 0) {
222 // CHRP compressed ROM image
223 D(bug("CHRP ROM image\n"));
224 uint32 lzss_offset, lzss_size;
225
226 char *s = strstr((char *)rom, "constant lzss-offset");
227 if (s == NULL)
228 throw rom_size_error();
229 s -= 7;
230 if (sscanf(s, "%06lx", &lzss_offset) != 1)
231 throw rom_size_error();
232 s = strstr((char *)rom, "constant lzss-size");
233 if (s == NULL)
234 throw rom_size_error();
235 s -= 7;
236 if (sscanf(s, "%06lx", &lzss_size) != 1)
237 throw rom_size_error();
238 D(bug("Offset of compressed data: %08lx\n", lzss_offset));
239 D(bug("Size of compressed data: %08lx\n", lzss_size));
240
241 D(bug("Uncompressing ROM...\n"));
242 uint8 *decoded = new uint8[ROM_SIZE];
243 decode_lzss(rom + lzss_offset, decoded, lzss_size);
244 memcpy((void *)(ROM_BASE + 0x100000), decoded + 0x100000, ROM_SIZE - 0x100000);
245 delete[] decoded;
246 delete[] rom;
247 } else if (rom_size != 4*1024*1024)
248 throw rom_size_error();
249 else
250 throw file_read_error();
251 }
252 }
253
254
255 /*
256 * Patch PowerMac ROM
257 */
258
259 // ROM type
260 enum {
261 ROMTYPE_TNT,
262 ROMTYPE_ALCHEMY,
263 ROMTYPE_ZANZIBAR,
264 ROMTYPE_GAZELLE,
265 ROMTYPE_NEWWORLD
266 };
267 static int ROMType;
268
269 // Nanokernel boot routine patches
270 static bool patch_nanokernel_boot(void)
271 {
272 uint32 *lp;
273 int i;
274
275 // Patch ConfigInfo
276 lp = (uint32 *)(ROM_BASE + 0x30d000);
277 lp[0x9c >> 2] = KernelDataAddr; // LA_InfoRecord
278 lp[0xa0 >> 2] = KernelDataAddr; // LA_KernelData
279 lp[0xa4 >> 2] = KernelDataAddr + 0x1000;// LA_EmulatorData
280 lp[0xa8 >> 2] = ROM_BASE + 0x480000; // LA_DispatchTable
281 lp[0xac >> 2] = ROM_BASE + 0x460000; // LA_EmulatorCode
282 lp[0x360 >> 2] = 0; // Physical RAM base (? on NewWorld ROM, this contains -1)
283 lp[0xfd8 >> 2] = ROM_BASE + 0x2a; // 68k reset vector
284
285 // Skip SR/BAT/SDR init
286 if (ROMType == ROMTYPE_GAZELLE || ROMType == ROMTYPE_NEWWORLD) {
287 lp = (uint32 *)(ROM_BASE + 0x310000);
288 *lp++ = POWERPC_NOP;
289 *lp = 0x38000000;
290 }
291 static const uint32 sr_init_loc[] = {0x3101b0, 0x3101b0, 0x3101b0, 0x3101ec, 0x310200};
292 lp = (uint32 *)(ROM_BASE + 0x310008);
293 *lp = 0x48000000 | (sr_init_loc[ROMType] - 8) & 0xffff; // b ROM_BASE+0x3101b0
294 lp = (uint32 *)(ROM_BASE + sr_init_loc[ROMType]);
295 *lp++ = 0x80200000 + XLM_KERNEL_DATA; // lwz r1,(pointer to Kernel Data)
296 *lp++ = 0x3da0dead; // lis r13,0xdead (start of kernel memory)
297 *lp++ = 0x3dc00010; // lis r14,0x0010 (size of page table)
298 *lp = 0x3de00010; // lis r15,0x0010 (size of kernel memory)
299
300 // Don't read PVR
301 static const uint32 pvr_loc[] = {0x3103b0, 0x3103b4, 0x3103b4, 0x310400, 0x310438};
302 lp = (uint32 *)(ROM_BASE + pvr_loc[ROMType]);
303 *lp = 0x81800000 + XLM_PVR; // lwz r12,(theoretical PVR)
304
305 // Set CPU specific data (even if ROM doesn't have support for that CPU)
306 lp = (uint32 *)(ROM_BASE + pvr_loc[ROMType]);
307 if (ntohl(lp[6]) != 0x2c0c0001)
308 return false;
309 uint32 ofs = lp[7] & 0xffff;
310 lp[8] = (lp[8] & 0xffff) | 0x48000000; // beq -> b
311 uint32 loc = (lp[8] & 0xffff) + (uint32)(lp+8) - ROM_BASE;
312 lp = (uint32 *)(ROM_BASE + ofs + 0x310000);
313 switch (PVR >> 16) {
314 case 1: // 601
315 lp[0] = 0x1000; // Page size
316 lp[1] = 0x8000; // Data cache size
317 lp[2] = 0x8000; // Inst cache size
318 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
319 lp[4] = 0x00010040; // Unified caches/Inst cache line size
320 lp[5] = 0x00400020; // Data cache line size/Data cache block size touch
321 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
322 lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc
323 lp[8] = 0x01000002; // TLB total size/TLB assoc
324 break;
325 case 3: // 603
326 lp[0] = 0x1000; // Page size
327 lp[1] = 0x2000; // Data cache size
328 lp[2] = 0x2000; // Inst cache size
329 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
330 lp[4] = 0x00000020; // Unified caches/Inst cache line size
331 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
332 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
333 lp[7] = 0x00020002; // Inst cache assoc/Data cache assoc
334 lp[8] = 0x00400002; // TLB total size/TLB assoc
335 break;
336 case 4: // 604
337 lp[0] = 0x1000; // Page size
338 lp[1] = 0x4000; // Data cache size
339 lp[2] = 0x4000; // Inst cache size
340 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
341 lp[4] = 0x00000020; // Unified caches/Inst cache line size
342 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
343 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
344 lp[7] = 0x00040004; // Inst cache assoc/Data cache assoc
345 lp[8] = 0x00800002; // TLB total size/TLB assoc
346 break;
347 // case 5: // 740?
348 case 6: // 603e
349 case 7: // 603ev
350 lp[0] = 0x1000; // Page size
351 lp[1] = 0x4000; // Data cache size
352 lp[2] = 0x4000; // Inst cache size
353 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
354 lp[4] = 0x00000020; // Unified caches/Inst cache line size
355 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
356 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
357 lp[7] = 0x00040004; // Inst cache assoc/Data cache assoc
358 lp[8] = 0x00400002; // TLB total size/TLB assoc
359 break;
360 case 8: // 750
361 lp[0] = 0x1000; // Page size
362 lp[1] = 0x8000; // Data cache size
363 lp[2] = 0x8000; // Inst cache size
364 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
365 lp[4] = 0x00000020; // Unified caches/Inst cache line size
366 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
367 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
368 lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc
369 lp[8] = 0x00800002; // TLB total size/TLB assoc
370 break;
371 case 9: // 604e
372 case 10: // 604ev5
373 lp[0] = 0x1000; // Page size
374 lp[1] = 0x8000; // Data cache size
375 lp[2] = 0x8000; // Inst cache size
376 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
377 lp[4] = 0x00000020; // Unified caches/Inst cache line size
378 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
379 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
380 lp[7] = 0x00040004; // Inst cache assoc/Data cache assoc
381 lp[8] = 0x00800002; // TLB total size/TLB assoc
382 break;
383 // case 11: // X704?
384 case 12: // ???
385 lp[0] = 0x1000; // Page size
386 lp[1] = 0x8000; // Data cache size
387 lp[2] = 0x8000; // Inst cache size
388 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
389 lp[4] = 0x00000020; // Unified caches/Inst cache line size
390 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
391 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
392 lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc
393 lp[8] = 0x00800002; // TLB total size/TLB assoc
394 break;
395 case 13: // ???
396 lp[0] = 0x1000; // Page size
397 lp[1] = 0x8000; // Data cache size
398 lp[2] = 0x8000; // Inst cache size
399 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
400 lp[4] = 0x00000020; // Unified caches/Inst cache line size
401 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
402 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
403 lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc
404 lp[8] = 0x01000004; // TLB total size/TLB assoc
405 break;
406 // case 50: // 821
407 // case 80: // 860
408 case 96: // ???
409 lp[0] = 0x1000; // Page size
410 lp[1] = 0x8000; // Data cache size
411 lp[2] = 0x8000; // Inst cache size
412 lp[3] = 0x00200020; // Coherency block size/Reservation granule size
413 lp[4] = 0x00010020; // Unified caches/Inst cache line size
414 lp[5] = 0x00200020; // Data cache line size/Data cache block size touch
415 lp[6] = 0x00200020; // Inst cache block size/Data cache block size
416 lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc
417 lp[8] = 0x00800004; // TLB total size/TLB assoc
418 break;
419 default:
420 printf("WARNING: Unknown CPU type\n");
421 break;
422 }
423
424 // Don't set SPRG3, don't test MQ
425 lp = (uint32 *)(ROM_BASE + loc + 0x20);
426 *lp++ = POWERPC_NOP;
427 lp++;
428 *lp++ = POWERPC_NOP;
429 lp++;
430 *lp = POWERPC_NOP;
431
432 // Don't read MSR
433 lp = (uint32 *)(ROM_BASE + loc + 0x40);
434 *lp = 0x39c00000; // li r14,0
435
436 // Don't write to DEC
437 lp = (uint32 *)(ROM_BASE + loc + 0x70);
438 *lp++ = POWERPC_NOP;
439 loc = (lp[0] & 0xffff) + (uint32)lp - ROM_BASE;
440
441 // Don't set SPRG3
442 lp = (uint32 *)(ROM_BASE + loc + 0x2c);
443 *lp = POWERPC_NOP;
444
445 // Don't read PVR
446 static const uint32 pvr_ofs[] = {0x138, 0x138, 0x138, 0x140, 0x148};
447 lp = (uint32 *)(ROM_BASE + loc + pvr_ofs[ROMType]);
448 *lp = 0x82e00000 + XLM_PVR; // lwz r23,(theoretical PVR)
449 lp = (uint32 *)(ROM_BASE + loc + 0x170);
450 if (*lp == 0x7eff42a6) // NewWorld ROM
451 *lp = 0x82e00000 + XLM_PVR; // lwz r23,(theoretical PVR)
452 lp = (uint32 *)(ROM_BASE + 0x313134);
453 if (*lp == 0x7e5f42a6)
454 *lp = 0x82400000 + XLM_PVR; // lwz r18,(theoretical PVR)
455 lp = (uint32 *)(ROM_BASE + 0x3131f4);
456 if (*lp == 0x7e5f42a6) // NewWorld ROM
457 *lp = 0x82400000 + XLM_PVR; // lwz r18,(theoretical PVR)
458
459 // Don't read SDR1
460 static const uint32 sdr1_ofs[] = {0x174, 0x174, 0x174, 0x17c, 0x19c};
461 lp = (uint32 *)(ROM_BASE + loc + sdr1_ofs[ROMType]);
462 *lp++ = 0x3d00dead; // lis r8,0xdead (pointer to page table)
463 *lp++ = 0x3ec0001f; // lis r22,0x001f (size of page table)
464 *lp = POWERPC_NOP;
465
466 // Don't clear page table
467 static const uint32 pgtb_ofs[] = {0x198, 0x198, 0x198, 0x1a0, 0x1c4};
468 lp = (uint32 *)(ROM_BASE + loc + pgtb_ofs[ROMType]);
469 *lp = POWERPC_NOP;
470
471 // Don't invalidate TLB
472 static const uint32 tlb_ofs[] = {0x1a0, 0x1a0, 0x1a0, 0x1a8, 0x1cc};
473 lp = (uint32 *)(ROM_BASE + loc + tlb_ofs[ROMType]);
474 *lp = POWERPC_NOP;
475
476 // Don't create RAM descriptor table
477 static const uint32 desc_ofs[] = {0x350, 0x350, 0x350, 0x358, 0x37c};
478 lp = (uint32 *)(ROM_BASE + loc + desc_ofs[ROMType]);
479 *lp = POWERPC_NOP;
480
481 // Don't load SRs and BATs
482 static const uint32 sr_ofs[] = {0x3d8, 0x3d8, 0x3d8, 0x3e0, 0x404};
483 lp = (uint32 *)(ROM_BASE + loc + sr_ofs[ROMType]);
484 *lp = POWERPC_NOP;
485
486 // Don't mess with SRs
487 static const uint32 sr2_ofs[] = {0x312118, 0x312118, 0x312118, 0x312118, 0x3121b4};
488 lp = (uint32 *)(ROM_BASE + sr2_ofs[ROMType]);
489 *lp = POWERPC_BLR;
490
491 // Don't check performance monitor
492 static const uint32 pm_ofs[] = {0x313148, 0x313148, 0x313148, 0x313148, 0x313218};
493 lp = (uint32 *)(ROM_BASE + pm_ofs[ROMType]);
494 while (*lp != 0x7e58eba6) lp++;
495 *lp++ = POWERPC_NOP;
496 while (*lp != 0x7e78eaa6) lp++;
497 *lp++ = POWERPC_NOP;
498 while (*lp != 0x7e59eba6) lp++;
499 *lp++ = POWERPC_NOP;
500 while (*lp != 0x7e79eaa6) lp++;
501 *lp++ = POWERPC_NOP;
502 while (*lp != 0x7e5aeba6) lp++;
503 *lp++ = POWERPC_NOP;
504 while (*lp != 0x7e7aeaa6) lp++;
505 *lp++ = POWERPC_NOP;
506 while (*lp != 0x7e5beba6) lp++;
507 *lp++ = POWERPC_NOP;
508 while (*lp != 0x7e7beaa6) lp++;
509 *lp++ = POWERPC_NOP;
510 while (*lp != 0x7e5feba6) lp++;
511 *lp++ = POWERPC_NOP;
512 while (*lp != 0x7e7feaa6) lp++;
513 *lp++ = POWERPC_NOP;
514 while (*lp != 0x7e5ceba6) lp++;
515 *lp++ = POWERPC_NOP;
516 while (*lp != 0x7e7ceaa6) lp++;
517 *lp++ = POWERPC_NOP;
518 while (*lp != 0x7e5deba6) lp++;
519 *lp++ = POWERPC_NOP;
520 while (*lp != 0x7e7deaa6) lp++;
521 *lp++ = POWERPC_NOP;
522 while (*lp != 0x7e5eeba6) lp++;
523 *lp++ = POWERPC_NOP;
524 while (*lp != 0x7e7eeaa6) lp++;
525 *lp++ = POWERPC_NOP;
526
527 // Jump to 68k emulator
528 static const uint32 jump68k_ofs[] = {0x40c, 0x40c, 0x40c, 0x414, 0x438};
529 lp = (uint32 *)(ROM_BASE + loc + jump68k_ofs[ROMType]);
530 *lp++ = 0x80610634; // lwz r3,0x0634(r1) (pointer to Emulator Data)
531 *lp++ = 0x8081119c; // lwz r4,0x119c(r1) (pointer to opcode table)
532 *lp++ = 0x80011184; // lwz r0,0x1184(r1) (pointer to emulator entry)
533 *lp++ = 0x7c0903a6; // mtctr r0
534 *lp = POWERPC_BCTR;
535 return true;
536 }
537
538 // 68k emulator patches
539 static bool patch_68k_emul(void)
540 {
541 uint32 *lp;
542 uint32 base;
543
544 // Overwrite twi instructions
545 static const uint32 twi_loc[] = {0x36e680, 0x36e6c0, 0x36e6c0, 0x36e6c0, 0x36e740};
546 base = twi_loc[ROMType];
547 lp = (uint32 *)(ROM_BASE + base);
548 *lp++ = 0x48000000 + 0x36f900 - base; // b 0x36f900 (Emulator start)
549 *lp++ = POWERPC_ILLEGAL;
550 *lp++ = 0x48000000 + 0x36fb00 - base - 8; // b 0x36fb00 (Reset opcode)
551 *lp++ = POWERPC_ILLEGAL;
552 *lp++ = POWERPC_ILLEGAL;
553 *lp++ = POWERPC_ILLEGAL;
554 *lp++ = POWERPC_ILLEGAL;
555 *lp++ = POWERPC_ILLEGAL;
556 *lp++ = POWERPC_ILLEGAL;
557 *lp++ = POWERPC_ILLEGAL;
558 *lp++ = POWERPC_ILLEGAL;
559 *lp++ = POWERPC_ILLEGAL;
560 *lp++ = POWERPC_ILLEGAL;
561 *lp++ = POWERPC_ILLEGAL;
562 *lp++ = POWERPC_ILLEGAL;
563 *lp++ = POWERPC_ILLEGAL;
564
565 // Set reset stack pointer
566 lp = (uint32 *)(ROM_BASE + base + 0xf0);
567 *lp++ = 0x80200000 + XLM_RESET_STACK; // lwz r1,XLM_RESET_STACK
568
569 // Install EXEC_RETURN and EMUL_OP opcodes
570 lp = (uint32 *)(ROM_BASE + 0x380000 + (M68K_EXEC_RETURN << 3));
571 *lp++ = 0x80000000 + XLM_EXEC_RETURN_PROC; // lwz r0,XLM_EXEC_RETURN_PROC
572 *lp++ = 0x4bfb6ffc; // b 0x36f800
573 for (int i=0; i<M68K_EMUL_OP_MAX-M68K_EMUL_BREAK; i++) {
574 *lp++ = 0x38a00000 + i + M68K_EMUL_BREAK; // li r5,M68K_EMUL_OP_*
575 *lp++ = 0x4bfb6ffc - i*8; // b 0x36f808
576 }
577
578 // Special handling for M68K_EMUL_OP_SHUTDOWN because Basilisk II is running
579 // on the 68k stack and simply quitting would delete the RAM area leaving
580 // the stack pointer in unaccessible memory
581 lp = (uint32 *)(ROM_BASE + 0x380000 + (M68K_EMUL_OP_SHUTDOWN << 3));
582 *lp++ = 0x80000000 + XLM_EMUL_RETURN_PROC; // lwz r0,XLM_EMUL_RETURN_PROC
583 *lp++ = 0x4bfb6ffc - (M68K_EMUL_OP_SHUTDOWN - M68K_EXEC_RETURN) * 8; // b 0x36f800
584
585 // Extra routines for EMUL_RETURN/EXEC_RETURN/EMUL_OP
586 lp = (uint32 *)(ROM_BASE + 0x36f800);
587 *lp++ = 0x7c0803a6; // mtlr r0
588 *lp++ = 0x4e800020; // blr
589
590 *lp++ = 0x80000000 + XLM_EMUL_OP_PROC; // lwz r0,XLM_EMUL_OP_PROC
591 *lp++ = 0x7c0803a6; // mtlr r0
592 *lp++ = 0x4e800020; // blr
593
594 // Extra routine for 68k emulator start
595 lp = (uint32 *)(ROM_BASE + 0x36f900);
596 *lp++ = 0x7c2903a6; // mtctr r1
597 *lp++ = 0x80200000 + XLM_IRQ_NEST; // lwz r1,XLM_IRQ_NEST
598 *lp++ = 0x38210001; // addi r1,r1,1
599 *lp++ = 0x90200000 + XLM_IRQ_NEST; // stw r1,XLM_IRQ_NEST
600 *lp++ = 0x80200000 + XLM_KERNEL_DATA;// lwz r1,XLM_KERNEL_DATA
601 *lp++ = 0x90c10018; // stw r6,0x18(r1)
602 *lp++ = 0x7cc902a6; // mfctr r6
603 *lp++ = 0x90c10004; // stw r6,$0004(r1)
604 *lp++ = 0x80c1065c; // lwz r6,$065c(r1)
605 *lp++ = 0x90e6013c; // stw r7,$013c(r6)
606 *lp++ = 0x91060144; // stw r8,$0144(r6)
607 *lp++ = 0x9126014c; // stw r9,$014c(r6)
608 *lp++ = 0x91460154; // stw r10,$0154(r6)
609 *lp++ = 0x9166015c; // stw r11,$015c(r6)
610 *lp++ = 0x91860164; // stw r12,$0164(r6)
611 *lp++ = 0x91a6016c; // stw r13,$016c(r6)
612 *lp++ = 0x7da00026; // mfcr r13
613 *lp++ = 0x80e10660; // lwz r7,$0660(r1)
614 *lp++ = 0x7d8802a6; // mflr r12
615 *lp++ = 0x50e74001; // rlwimi. r7,r7,8,$80000000
616 *lp++ = 0x814105f0; // lwz r10,0x05f0(r1)
617 *lp++ = 0x7d4803a6; // mtlr r10
618 *lp++ = 0x7d8a6378; // mr r10,r12
619 *lp++ = 0x3d600002; // lis r11,0x0002
620 *lp++ = 0x616bf072; // ori r11,r11,0xf072 (MSR)
621 *lp++ = 0x50e7deb4; // rlwimi r7,r7,27,$00000020
622 *lp++ = 0x4e800020; // blr
623
624 // Extra routine for Reset opcode
625 lp = (uint32 *)(ROM_BASE + 0x36fc00);
626 *lp++ = 0x7c2903a6; // mtctr r1
627 *lp++ = 0x80200000 + XLM_IRQ_NEST; // lwz r1,XLM_IRQ_NEST
628 *lp++ = 0x38210001; // addi r1,r1,1
629 *lp++ = 0x90200000 + XLM_IRQ_NEST; // stw r1,XLM_IRQ_NEST
630 *lp++ = 0x80200000 + XLM_KERNEL_DATA;// lwz r1,XLM_KERNEL_DATA
631 *lp++ = 0x90c10018; // stw r6,0x18(r1)
632 *lp++ = 0x7cc902a6; // mfctr r6
633 *lp++ = 0x90c10004; // stw r6,$0004(r1)
634 *lp++ = 0x80c1065c; // lwz r6,$065c(r1)
635 *lp++ = 0x90e6013c; // stw r7,$013c(r6)
636 *lp++ = 0x91060144; // stw r8,$0144(r6)
637 *lp++ = 0x9126014c; // stw r9,$014c(r6)
638 *lp++ = 0x91460154; // stw r10,$0154(r6)
639 *lp++ = 0x9166015c; // stw r11,$015c(r6)
640 *lp++ = 0x91860164; // stw r12,$0164(r6)
641 *lp++ = 0x91a6016c; // stw r13,$016c(r6)
642 *lp++ = 0x7da00026; // mfcr r13
643 *lp++ = 0x80e10660; // lwz r7,$0660(r1)
644 *lp++ = 0x7d8802a6; // mflr r12
645 *lp++ = 0x50e74001; // rlwimi. r7,r7,8,$80000000
646 *lp++ = 0x814105f4; // lwz r10,0x05f8(r1)
647 *lp++ = 0x7d4803a6; // mtlr r10
648 *lp++ = 0x7d8a6378; // mr r10,r12
649 *lp++ = 0x3d600002; // lis r11,0x0002
650 *lp++ = 0x616bf072; // ori r11,r11,0xf072 (MSR)
651 *lp++ = 0x50e7deb4; // rlwimi r7,r7,27,$00000020
652 *lp++ = 0x4e800020; // blr
653
654 // Patch DR emulator to jump to right address when an interrupt occurs
655 lp = (uint32 *)(ROM_BASE + 0x370000);
656 while (lp < (uint32 *)(ROM_BASE + 0x380000)) {
657 if (*lp == 0x4ca80020) // bclr 5,8
658 goto dr_found;
659 lp++;
660 }
661 D(bug("DR emulator patch location not found\n"));
662 return false;
663 dr_found:
664 lp++;
665 *lp = 0x48000000 + 0xf000 - ((uint32)lp & 0xffff); // b DR_CACHE_BASE+0x1f000
666 lp = (uint32 *)(ROM_BASE + 0x37f000);
667 *lp++ = 0x3c000000 + ((ROM_BASE + 0x46d0a4) >> 16); // lis r0,xxx
668 *lp++ = 0x60000000 + ((ROM_BASE + 0x46d0a4) & 0xffff); // ori r0,r0,xxx
669 *lp++ = 0x7c0903a6; // mtctr r0
670 *lp = POWERPC_BCTR; // bctr
671 return true;
672 }
673
674 // Nanokernel patches
675 static bool patch_nanokernel(void)
676 {
677 uint32 *lp;
678
679 // Patch 68k emulator trap routine
680 lp = (uint32 *)(ROM_BASE + 0x312994); // Always restore FPU state
681 while (*lp != 0x39260040) lp++;
682 lp--;
683 *lp = 0x48000441; // bl 0x00312dd4
684 lp = (uint32 *)(ROM_BASE + 0x312dd8); // Don't modify MSR to turn on FPU
685 while (*lp != 0x810600e4) lp++;
686 lp--;
687 *lp++ = POWERPC_NOP;
688 lp += 2;
689 *lp++ = POWERPC_NOP;
690 lp++;
691 *lp++ = POWERPC_NOP;
692 *lp++ = POWERPC_NOP;
693 *lp = POWERPC_NOP;
694
695 // Patch trap return routine
696 lp = (uint32 *)(ROM_BASE + 0x312c20);
697 while (*lp != 0x7d5a03a6) lp++;
698 *lp++ = 0x7d4903a6; // mtctr r10
699 *lp++ = 0x7daff120; // mtcr r13
700 *lp++ = 0x48000000 + 0x8000 - ((uint32)lp & 0xffff); // b ROM_BASE+0x318000
701 uint32 xlp = (uint32)lp & 0xffff;
702
703 lp = (uint32 *)(ROM_BASE + 0x312c50); // Replace rfi
704 while (*lp != 0x4c000064) lp++;
705 *lp = POWERPC_BCTR;
706
707 lp = (uint32 *)(ROM_BASE + 0x318000);
708 *lp++ = 0x81400000 + XLM_IRQ_NEST; // lwz r10,XLM_IRQ_NEST
709 *lp++ = 0x394affff; // subi r10,r10,1
710 *lp++ = 0x91400000 + XLM_IRQ_NEST; // stw r10,XLM_IRQ_NEST
711 *lp = 0x48000000 + ((xlp - 0x800c) & 0x03fffffc); // b ROM_BASE+0x312c2c
712 return true;
713 }
714
715 static bool patch_rom(void)
716 {
717 // Detect ROM type
718 if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot TNT", 8))
719 ROMType = ROMTYPE_TNT;
720 else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Alchemy", 12))
721 ROMType = ROMTYPE_ALCHEMY;
722 else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Zanzibar", 13))
723 ROMType = ROMTYPE_ZANZIBAR;
724 else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Gazelle", 12))
725 ROMType = ROMTYPE_GAZELLE;
726 else if (!memcmp((void *)(ROM_BASE + 0x30d064), "NewWorld", 8))
727 ROMType = ROMTYPE_NEWWORLD;
728 else
729 return false;
730
731 // Apply patches
732 if (!patch_nanokernel_boot()) return false;
733 if (!patch_68k_emul()) return false;
734 if (!patch_nanokernel()) return false;
735
736 // Copy 68k emulator to 2MB boundary
737 memcpy((void *)(ROM_BASE + ROM_SIZE), (void *)(ROM_BASE + ROM_SIZE - 0x100000), 0x100000);
738 return true;
739 }
740
741
742 /*
743 * Initialize 680x0 emulation
744 */
745
746 static asm void *get_toc(void)
747 {
748 mr r3,r2
749 blr
750 }
751
752 bool Init680x0(void)
753 {
754 char str[256];
755
756 // Mac address space = host address space
757 RAMBaseMac = (uint32)RAMBaseHost;
758 ROMBaseMac = (uint32)ROMBaseHost;
759
760 // Get TOC pointer
761 TOC = get_toc();
762
763 // Get system info
764 get_system_info(&SysInfo);
765 switch (SysInfo.cpu_type) {
766 case B_CPU_PPC_601:
767 PVR = 0x00010000;
768 break;
769 case B_CPU_PPC_603:
770 PVR = 0x00030000;
771 break;
772 case B_CPU_PPC_603e:
773 PVR = 0x00060000;
774 break;
775 case B_CPU_PPC_604:
776 PVR = 0x00040000;
777 break;
778 case B_CPU_PPC_604e:
779 PVR = 0x00090000;
780 break;
781 default:
782 PVR = 0x00040000;
783 break;
784 }
785 CPUClockSpeed = SysInfo.cpu_clock_speed;
786 BusClockSpeed = SysInfo.bus_clock_speed;
787
788 // Delete old areas
789 area_id old_kernel_area = find_area(KERNEL_AREA_NAME);
790 if (old_kernel_area > 0)
791 delete_area(old_kernel_area);
792 area_id old_dr_cache_area = find_area(DR_CACHE_AREA_NAME);
793 if (old_dr_cache_area > 0)
794 delete_area(old_dr_cache_area);
795
796 // Create area for Kernel Data
797 kernel_data = (KernelData *)0x68ffe000;
798 kernel_area = create_area(KERNEL_AREA_NAME, &kernel_data, B_EXACT_ADDRESS, 0x2000, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
799 if (kernel_area < 0) {
800 sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(kernel_area), kernel_area);
801 ErrorAlert(str);
802 return false;
803 }
804 emulator_data = &kernel_data->ed;
805 KernelDataAddr = (uint32)kernel_data;
806 D(bug("Kernel Data area %ld at %p, Emulator Data at %p\n", kernel_area, kernel_data, emulator_data));
807
808 // Load PowerMac ROM (upper 3MB)
809 try {
810 load_rom();
811 } catch (file_open_error) {
812 ErrorAlert(STR_NO_ROM_FILE_ERR);
813 return false;
814 } catch (file_read_error) {
815 ErrorAlert(STR_ROM_FILE_READ_ERR);
816 return false;
817 } catch (rom_size_error) {
818 ErrorAlert(STR_ROM_SIZE_ERR);
819 return false;
820 }
821
822 // Install ROM patches
823 if (!patch_rom()) {
824 ErrorAlert("Unsupported PowerMac ROM version");
825 return false;
826 }
827
828 // Create area for DR Cache
829 DRCacheAddr = DR_CACHE_BASE;
830 dr_cache_area = create_area(DR_CACHE_AREA_NAME, (void **)&DRCacheAddr, B_EXACT_ADDRESS, DR_CACHE_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
831 if (dr_cache_area < 0) {
832 sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(dr_cache_area), dr_cache_area);
833 ErrorAlert(str);
834 return false;
835 }
836 D(bug("DR Cache area %ld at %p\n", dr_cache_area, DRCacheAddr));
837
838 // Initialize Kernel Data
839 memset(kernel_data, 0, sizeof(KernelData));
840 if (ROMType == ROMTYPE_NEWWORLD) {
841 kernel_data->v[0xc20 >> 2] = RAMSize;
842 kernel_data->v[0xc24 >> 2] = RAMSize;
843 kernel_data->v[0xc30 >> 2] = RAMSize;
844 kernel_data->v[0xc34 >> 2] = RAMSize;
845 kernel_data->v[0xc38 >> 2] = 0x00010020;
846 kernel_data->v[0xc3c >> 2] = 0x00200001;
847 kernel_data->v[0xc40 >> 2] = 0x00010000;
848 kernel_data->v[0xc50 >> 2] = RAMBaseMac;
849 kernel_data->v[0xc54 >> 2] = RAMSize;
850 kernel_data->v[0xf60 >> 2] = PVR;
851 kernel_data->v[0xf64 >> 2] = CPUClockSpeed;
852 kernel_data->v[0xf68 >> 2] = BusClockSpeed;
853 kernel_data->v[0xf6c >> 2] = CPUClockSpeed;
854 } else {
855 kernel_data->v[0xc80 >> 2] = RAMSize;
856 kernel_data->v[0xc84 >> 2] = RAMSize;
857 kernel_data->v[0xc90 >> 2] = RAMSize;
858 kernel_data->v[0xc94 >> 2] = RAMSize;
859 kernel_data->v[0xc98 >> 2] = 0x00010020;
860 kernel_data->v[0xc9c >> 2] = 0x00200001;
861 kernel_data->v[0xca0 >> 2] = 0x00010000;
862 kernel_data->v[0xcb0 >> 2] = RAMBaseMac;
863 kernel_data->v[0xcb4 >> 2] = RAMSize;
864 kernel_data->v[0xf80 >> 2] = PVR;
865 kernel_data->v[0xf84 >> 2] = CPUClockSpeed;
866 kernel_data->v[0xf88 >> 2] = BusClockSpeed;
867 kernel_data->v[0xf8c >> 2] = CPUClockSpeed;
868 }
869
870 // Initialize extra low memory
871 memset((void *)0x2000, 0, 0x1000);
872 *(uint32 *)XLM_RESET_STACK = 0x2000; // Reset stack pointer
873 *(KernelData **)XLM_KERNEL_DATA = kernel_data;// For trap replacement routines
874 *(void **)XLM_TOC = TOC; // TOC pointer of emulator
875 *(uint32 *)XLM_PVR = PVR; // Theoretical PVR
876
877 // Clear caches (as we loaded and patched code)
878 clear_caches((void *)ROM_BASE, ROM_AREA_SIZE, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE);
879 return true;
880 }
881
882
883 /*
884 * Deinitialize 680x0 emulation
885 */
886
887 void Exit680x0(void)
888 {
889 // Delete DR Cache area
890 if (dr_cache_area >= 0)
891 delete_area(dr_cache_area);
892
893 // Delete Kernel Data area
894 if (kernel_area >= 0)
895 delete_area(kernel_area);
896 }
897
898
899 /*
900 * Quit emulator (must only be called from main thread)
901 */
902
903 asm void QuitEmulator(void)
904 {
905 lwz r0,XLM_EMUL_RETURN_PROC
906 mtlr r0
907 blr
908 }
909
910
911 /*
912 * Reset and start 680x0 emulation
913 */
914
915 static asm void jump_to_rom(register uint32 entry)
916 {
917 // Create stack frame
918 mflr r0
919 stw r0,8(r1)
920 mfcr r0
921 stw r0,4(r1)
922 stwu r1,-(56+19*4+18*8)(r1)
923
924 // Save PowerPC registers
925 stmw r13,56(r1)
926 stfd f14,56+19*4+0*8(r1)
927 stfd f15,56+19*4+1*8(r1)
928 stfd f16,56+19*4+2*8(r1)
929 stfd f17,56+19*4+3*8(r1)
930 stfd f18,56+19*4+4*8(r1)
931 stfd f19,56+19*4+5*8(r1)
932 stfd f20,56+19*4+6*8(r1)
933 stfd f21,56+19*4+7*8(r1)
934 stfd f22,56+19*4+8*8(r1)
935 stfd f23,56+19*4+9*8(r1)
936 stfd f24,56+19*4+10*8(r1)
937 stfd f25,56+19*4+11*8(r1)
938 stfd f26,56+19*4+12*8(r1)
939 stfd f27,56+19*4+13*8(r1)
940 stfd f28,56+19*4+14*8(r1)
941 stfd f29,56+19*4+15*8(r1)
942 stfd f30,56+19*4+16*8(r1)
943 stfd f31,56+19*4+17*8(r1)
944
945 // Move entry address to ctr, get pointer to Emulator Data
946 mtctr r3
947 lwz r3,emulator_data(r2)
948
949 // Skip over EMUL_RETURN routine and get its address
950 bl @1
951
952
953 /*
954 * EMUL_RETURN: Returned from emulator
955 */
956
957 // Restore PowerPC registers
958 lwz r1,XLM_EMUL_RETURN_STACK
959 lwz r2,XLM_TOC
960 lmw r13,56(r1)
961 lfd f14,56+19*4+0*8(r1)
962 lfd f15,56+19*4+1*8(r1)
963 lfd f16,56+19*4+2*8(r1)
964 lfd f17,56+19*4+3*8(r1)
965 lfd f18,56+19*4+4*8(r1)
966 lfd f19,56+19*4+5*8(r1)
967 lfd f20,56+19*4+6*8(r1)
968 lfd f21,56+19*4+7*8(r1)
969 lfd f22,56+19*4+8*8(r1)
970 lfd f23,56+19*4+9*8(r1)
971 lfd f24,56+19*4+10*8(r1)
972 lfd f25,56+19*4+11*8(r1)
973 lfd f26,56+19*4+12*8(r1)
974 lfd f27,56+19*4+13*8(r1)
975 lfd f28,56+19*4+14*8(r1)
976 lfd f29,56+19*4+15*8(r1)
977 lfd f30,56+19*4+16*8(r1)
978 lfd f31,56+19*4+17*8(r1)
979
980 // Exiting from 68k emulator
981 li r0,1
982 stw r0,XLM_IRQ_NEST
983 li r0,MODE_EMUL_OP
984 stw r0,XLM_RUN_MODE
985
986 // Return to caller of jump_to_rom()
987 lwz r0,56+19*4+18*8+8(r1)
988 mtlr r0
989 lwz r0,56+19*4+18*8+4(r1)
990 mtcrf 0xff,r0
991 addi r1,r1,56+19*4+18*8
992 blr
993
994
995 // Save address of EMUL_RETURN routine for 68k emulator patch
996 @1 mflr r0
997 stw r0,XLM_EMUL_RETURN_PROC
998
999 // Skip over EXEC_RETURN routine and get its address
1000 bl @2
1001
1002
1003 /*
1004 * EXEC_RETURN: Returned from 68k routine executed with Execute68k()
1005 */
1006
1007 // Save r25 (contains current 68k interrupt level)
1008 stw r25,XLM_68K_R25
1009
1010 // Reentering EMUL_OP mode
1011 li r0,MODE_EMUL_OP
1012 stw r0,XLM_RUN_MODE
1013
1014 // Save 68k registers
1015 lwz r4,56+19*4+18*8+12(r1)
1016 stw r8,M68kRegisters.d[0](r4)
1017 stw r9,M68kRegisters.d[1](r4)
1018 stw r10,M68kRegisters.d[2](r4)
1019 stw r11,M68kRegisters.d[3](r4)
1020 stw r12,M68kRegisters.d[4](r4)
1021 stw r13,M68kRegisters.d[5](r4)
1022 stw r14,M68kRegisters.d[6](r4)
1023 stw r15,M68kRegisters.d[7](r4)
1024 stw r16,M68kRegisters.a[0](r4)
1025 stw r17,M68kRegisters.a[1](r4)
1026 stw r18,M68kRegisters.a[2](r4)
1027 stw r19,M68kRegisters.a[3](r4)
1028 stw r20,M68kRegisters.a[4](r4)
1029 stw r21,M68kRegisters.a[5](r4)
1030 stw r22,M68kRegisters.a[6](r4)
1031
1032 // Restore PowerPC registers
1033 lmw r13,56(r1)
1034 #if SAVE_FP_EXEC_68K
1035 lfd f14,56+19*4+0*8(r1)
1036 lfd f15,56+19*4+1*8(r1)
1037 lfd f16,56+19*4+2*8(r1)
1038 lfd f17,56+19*4+3*8(r1)
1039 lfd f18,56+19*4+4*8(r1)
1040 lfd f19,56+19*4+5*8(r1)
1041 lfd f20,56+19*4+6*8(r1)
1042 lfd f21,56+19*4+7*8(r1)
1043 lfd f22,56+19*4+8*8(r1)
1044 lfd f23,56+19*4+9*8(r1)
1045 lfd f24,56+19*4+10*8(r1)
1046 lfd f25,56+19*4+11*8(r1)
1047 lfd f26,56+19*4+12*8(r1)
1048 lfd f27,56+19*4+13*8(r1)
1049 lfd f28,56+19*4+14*8(r1)
1050 lfd f29,56+19*4+15*8(r1)
1051 lfd f30,56+19*4+16*8(r1)
1052 lfd f31,56+19*4+17*8(r1)
1053 #endif
1054
1055 // Return to caller
1056 lwz r0,56+19*4+18*8+8(r1)
1057 mtlr r0
1058 addi r1,r1,56+19*4+18*8
1059 blr
1060
1061
1062 // Stave address of EXEC_RETURN routine for 68k emulator patch
1063 @2 mflr r0
1064 stw r0,XLM_EXEC_RETURN_PROC
1065
1066 // Skip over EMUL_OP routine and get its address
1067 bl @3
1068
1069
1070 /*
1071 * EMUL_OP: Execute native routine, selector in r5 (my own private mode switch)
1072 *
1073 * 68k registers are stored in a M68kRegisters struct on the stack
1074 * which the native routine may read and modify
1075 */
1076
1077 // Save r25 (contains current 68k interrupt level)
1078 stw r25,XLM_68K_R25
1079
1080 // Entering EMUL_OP mode within 68k emulator
1081 li r0,MODE_EMUL_OP
1082 stw r0,XLM_RUN_MODE
1083
1084 // Create PowerPC stack frame, reserve space for M68kRegisters
1085 mr r3,r1
1086 subi r1,r1,56 // Fake "caller" frame
1087 rlwinm r1,r1,0,0,29 // Align stack
1088
1089 mfcr r0
1090 rlwinm r0,r0,0,11,8
1091 stw r0,4(r1)
1092 mfxer r0
1093 stw r0,16(r1)
1094 stw r2,12(r1)
1095 stwu r1,-(56+16*4+15*8)(r1)
1096 lwz r2,XLM_TOC
1097
1098 // Save 68k registers
1099 stw r8,56+M68kRegisters.d[0](r1)
1100 stw r9,56+M68kRegisters.d[1](r1)
1101 stw r10,56+M68kRegisters.d[2](r1)
1102 stw r11,56+M68kRegisters.d[3](r1)
1103 stw r12,56+M68kRegisters.d[4](r1)
1104 stw r13,56+M68kRegisters.d[5](r1)
1105 stw r14,56+M68kRegisters.d[6](r1)
1106 stw r15,56+M68kRegisters.d[7](r1)
1107 stw r16,56+M68kRegisters.a[0](r1)
1108 stw r17,56+M68kRegisters.a[1](r1)
1109 stw r18,56+M68kRegisters.a[2](r1)
1110 stw r19,56+M68kRegisters.a[3](r1)
1111 stw r20,56+M68kRegisters.a[4](r1)
1112 stw r21,56+M68kRegisters.a[5](r1)
1113 stw r22,56+M68kRegisters.a[6](r1)
1114 stw r3,56+M68kRegisters.a[7](r1)
1115 stfd f0,56+16*4+0*8(r1)
1116 stfd f1,56+16*4+1*8(r1)
1117 stfd f2,56+16*4+2*8(r1)
1118 stfd f3,56+16*4+3*8(r1)
1119 stfd f4,56+16*4+4*8(r1)
1120 stfd f5,56+16*4+5*8(r1)
1121 stfd f6,56+16*4+6*8(r1)
1122 stfd f7,56+16*4+7*8(r1)
1123 mffs f0
1124 stfd f8,56+16*4+8*8(r1)
1125 stfd f9,56+16*4+9*8(r1)
1126 stfd f10,56+16*4+10*8(r1)
1127 stfd f11,56+16*4+11*8(r1)
1128 stfd f12,56+16*4+12*8(r1)
1129 stfd f13,56+16*4+13*8(r1)
1130 stfd f0,56+16*4+14*8(r1)
1131
1132 // Execute native routine
1133 mr r3,r5
1134 addi r4,r1,56
1135 bl EmulOp
1136
1137 // Restore 68k registers
1138 lwz r8,56+M68kRegisters.d[0](r1)
1139 lwz r9,56+M68kRegisters.d[1](r1)
1140 lwz r10,56+M68kRegisters.d[2](r1)
1141 lwz r11,56+M68kRegisters.d[3](r1)
1142 lwz r12,56+M68kRegisters.d[4](r1)
1143 lwz r13,56+M68kRegisters.d[5](r1)
1144 lwz r14,56+M68kRegisters.d[6](r1)
1145 lwz r15,56+M68kRegisters.d[7](r1)
1146 lwz r16,56+M68kRegisters.a[0](r1)
1147 lwz r17,56+M68kRegisters.a[1](r1)
1148 lwz r18,56+M68kRegisters.a[2](r1)
1149 lwz r19,56+M68kRegisters.a[3](r1)
1150 lwz r20,56+M68kRegisters.a[4](r1)
1151 lwz r21,56+M68kRegisters.a[5](r1)
1152 lwz r22,56+M68kRegisters.a[6](r1)
1153 lwz r3,56+M68kRegisters.a[7](r1)
1154 lfd f13,56+16*4+14*8(r1)
1155 lfd f0,56+16*4+0*8(r1)
1156 lfd f1,56+16*4+1*8(r1)
1157 lfd f2,56+16*4+2*8(r1)
1158 lfd f3,56+16*4+3*8(r1)
1159 lfd f4,56+16*4+4*8(r1)
1160 lfd f5,56+16*4+5*8(r1)
1161 lfd f6,56+16*4+6*8(r1)
1162 lfd f7,56+16*4+7*8(r1)
1163 mtfsf 0xff,f13
1164 lfd f8,56+16*4+8*8(r1)
1165 lfd f9,56+16*4+9*8(r1)
1166 lfd f10,56+16*4+10*8(r1)
1167 lfd f11,56+16*4+11*8(r1)
1168 lfd f12,56+16*4+12*8(r1)
1169 lfd f13,56+16*4+13*8(r1)
1170
1171 // Delete PowerPC stack frame
1172 lwz r2,56+16*4+15*8+12(r1)
1173 lwz r0,56+16*4+15*8+16(r1)
1174 mtxer r0
1175 lwz r0,56+16*4+15*8+4(r1)
1176 mtcrf 0xff,r0
1177 mr r1,r3
1178
1179 // Reeintering 68k emulator
1180 li r0,MODE_68K
1181 stw r0,XLM_RUN_MODE
1182
1183 // Set r0 to 0 for 68k emulator
1184 li r0,0
1185
1186 // Execute next 68k opcode
1187 rlwimi r29,r27,3,13,28
1188 lhau r27,2(r24)
1189 mtlr r29
1190 blr
1191
1192
1193 // Save address of EMUL_OP routine for 68k emulator patch
1194 @3 mflr r0
1195 stw r0,XLM_EMUL_OP_PROC
1196
1197 // Save stack pointer for EMUL_RETURN
1198 stw r1,XLM_EMUL_RETURN_STACK
1199
1200 // Preset registers for ROM boot routine
1201 lis r3,0x40b0 // Pointer to ROM boot structure
1202 ori r3,r3,0xd000
1203
1204 // 68k emulator is now active
1205 li r0,MODE_68K
1206 stw r0,XLM_RUN_MODE
1207
1208 // Jump to ROM
1209 bctr
1210 }
1211
1212 void Start680x0(void)
1213 {
1214 // Install interrupt signal handler
1215 sigemptyset(&sigusr1_action.sa_mask);
1216 sigusr1_action.sa_handler = (__signal_func_ptr)(sigusr1_handler);
1217 sigusr1_action.sa_flags = 0;
1218 sigusr1_action.sa_userdata = NULL;
1219 sigaction(SIGUSR1, &sigusr1_action, NULL);
1220
1221 // Install signal stack
1222 set_signal_stack(malloc(SIG_STACK_SIZE), SIG_STACK_SIZE);
1223
1224 // We're now ready to receive signals
1225 ReadyForSignals = true;
1226
1227 D(bug("Jumping to ROM\n"));
1228 jump_to_rom(ROM_BASE + 0x310000);
1229 D(bug("Returned from ROM\n"));
1230
1231 // We're no longer ready to receive signals
1232 ReadyForSignals = false;
1233 }
1234
1235
1236 /*
1237 * Trigger interrupt
1238 */
1239
1240 void TriggerInterrupt(void)
1241 {
1242 idle_resume();
1243 if (emul_thread > 0 && ReadyForSignals)
1244 send_signal(emul_thread, SIGUSR1);
1245 }
1246
1247 void TriggerNMI(void)
1248 {
1249 //!! not implemented yet
1250 }
1251
1252
1253 /*
1254 * Execute 68k subroutine
1255 * r->a[7] and r->sr are unused!
1256 */
1257
1258 static asm void execute_68k(register uint32 addr, register M68kRegisters *r)
1259 {
1260 // Create stack frame
1261 mflr r0
1262 stw r0,8(r1)
1263 stw r4,12(r1)
1264 stwu r1,-(56+19*4+18*8)(r1)
1265
1266 // Save PowerPC registers
1267 stmw r13,56(r1)
1268 #if SAVE_FP_EXEC_68K
1269 stfd f14,56+19*4+0*8(r1)
1270 stfd f15,56+19*4+1*8(r1)
1271 stfd f16,56+19*4+2*8(r1)
1272 stfd f17,56+19*4+3*8(r1)
1273 stfd f18,56+19*4+4*8(r1)
1274 stfd f19,56+19*4+5*8(r1)
1275 stfd f20,56+19*4+6*8(r1)
1276 stfd f21,56+19*4+7*8(r1)
1277 stfd f22,56+19*4+8*8(r1)
1278 stfd f23,56+19*4+9*8(r1)
1279 stfd f24,56+19*4+10*8(r1)
1280 stfd f25,56+19*4+11*8(r1)
1281 stfd f26,56+19*4+12*8(r1)
1282 stfd f27,56+19*4+13*8(r1)
1283 stfd f28,56+19*4+14*8(r1)
1284 stfd f29,56+19*4+15*8(r1)
1285 stfd f30,56+19*4+16*8(r1)
1286 stfd f31,56+19*4+17*8(r1)
1287 #endif
1288
1289 // Set up registers for 68k emulator
1290 lwz r31,XLM_KERNEL_DATA // Pointer to Kernel Data
1291 addi r31,r31,0x1000 // points to Emulator Data
1292 li r0,0
1293 mtcrf 0xff,r0
1294 creqv 11,11,11 // Supervisor mode
1295 lwz r8,M68kRegisters.d[0](r4)
1296 lwz r9,M68kRegisters.d[1](r4)
1297 lwz r10,M68kRegisters.d[2](r4)
1298 lwz r11,M68kRegisters.d[3](r4)
1299 lwz r12,M68kRegisters.d[4](r4)
1300 lwz r13,M68kRegisters.d[5](r4)
1301 lwz r14,M68kRegisters.d[6](r4)
1302 lwz r15,M68kRegisters.d[7](r4)
1303 lwz r16,M68kRegisters.a[0](r4)
1304 lwz r17,M68kRegisters.a[1](r4)
1305 lwz r18,M68kRegisters.a[2](r4)
1306 lwz r19,M68kRegisters.a[3](r4)
1307 lwz r20,M68kRegisters.a[4](r4)
1308 lwz r21,M68kRegisters.a[5](r4)
1309 lwz r22,M68kRegisters.a[6](r4)
1310 li r23,0
1311 mr r24,r3
1312 lwz r25,XLM_68K_R25 // MSB of SR
1313 li r26,0
1314 li r28,0 // VBR
1315 lwz r29,0x74(r31) // Pointer to opcode table
1316 lwz r30,0x78(r31) // Address of emulator
1317
1318 // Reentering 68k emulator
1319 li r0,MODE_68K
1320 stw r0,XLM_RUN_MODE
1321
1322 // Set r0 to 0 for 68k emulator
1323 li r0,0
1324
1325 // Execute 68k opcode
1326 lha r27,0(r24)
1327 rlwimi r29,r27,3,13,28
1328 lhau r27,2(r24)
1329 mtlr r29
1330 blr
1331 }
1332
1333 void Execute68k(uint32 addr, M68kRegisters *r)
1334 {
1335 uint16 proc[4] = {M68K_JSR, addr >> 16, addr & 0xffff, M68K_EXEC_RETURN};
1336 execute_68k((uint32)proc, r);
1337 }
1338
1339
1340 /*
1341 * Execute MacOS 68k trap
1342 * r->a[7] and r->sr are unused!
1343 */
1344
1345 void Execute68kTrap(uint16 trap, struct M68kRegisters *r)
1346 {
1347 uint16 proc[2] = {trap, M68K_EXEC_RETURN};
1348 execute_68k((uint32)proc, r);
1349 }
1350
1351
1352 /*
1353 * USR1 handler
1354 */
1355
1356 static void sigusr1_handler(int sig, void *arg, vregs *r)
1357 {
1358 // Do nothing if interrupts are disabled
1359 if ((*(int32 *)XLM_IRQ_NEST) > 0)
1360 return;
1361
1362 // 68k emulator active? Then trigger 68k interrupt level 1
1363 if (*(uint32 *)XLM_RUN_MODE == MODE_68K) {
1364 *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1;
1365 r->cr |= kernel_data->v[0x674 >> 2];
1366 }
1367 }