88 |
|
#include "macos_util.h" |
89 |
|
#include "rom_patches.h" |
90 |
|
#include "user_strings.h" |
91 |
+ |
#include "thunks.h" |
92 |
|
|
93 |
|
#include "sheep_driver.h" |
94 |
|
|
117 |
|
const char RAM_AREA_NAME[] = "Macintosh RAM"; |
118 |
|
const char ROM_AREA_NAME[] = "Macintosh ROM"; |
119 |
|
const char DR_CACHE_AREA_NAME[] = "Macintosh DR Cache"; |
120 |
< |
|
120 |
< |
const uint32 ROM_AREA_SIZE = 0x500000; // Size of ROM area |
121 |
< |
|
122 |
< |
const uint32 KERNEL_DATA_BASE = 0x68ffe000; // Address of Kernel Data |
123 |
< |
const uint32 KERNEL_DATA2_BASE = 0x5fffe000;// Alternate address of Kernel Data |
124 |
< |
const uint32 KERNEL_AREA_SIZE = 0x2000; // Size of Kernel Data area |
120 |
> |
const char SHEEP_AREA_NAME[] = "SheepShaver Virtual Stack"; |
121 |
|
|
122 |
|
const uint32 SIG_STACK_SIZE = 8192; // Size of signal stack |
123 |
|
|
124 |
|
const uint32 MSG_START = 'strt'; // Emulator start message |
125 |
|
|
126 |
|
|
131 |
– |
// Emulator Data |
132 |
– |
struct EmulatorData { |
133 |
– |
uint32 v[0x400]; |
134 |
– |
}; |
135 |
– |
|
136 |
– |
|
137 |
– |
// Kernel Data |
138 |
– |
struct KernelData { |
139 |
– |
uint32 v[0x400]; |
140 |
– |
EmulatorData ed; |
141 |
– |
}; |
142 |
– |
|
143 |
– |
|
127 |
|
// Application object |
128 |
|
class SheepShaver : public BApplication { |
129 |
|
public: |
220 |
|
|
221 |
|
static void *sig_stack = NULL; // Stack for signal handlers |
222 |
|
static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler |
223 |
+ |
uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros |
224 |
+ |
uintptr SheepMem::base; // Address of SheepShaver data |
225 |
+ |
uintptr SheepMem::top; // Top of SheepShaver data (stack like storage) |
226 |
+ |
static area_id SheepMemArea; // SheepShaver data area ID |
227 |
|
|
228 |
|
|
229 |
|
// Prototypes |
359 |
|
void SheepShaver::StartEmulator(void) |
360 |
|
{ |
361 |
|
char str[256]; |
362 |
+ |
int16 i16; |
363 |
|
|
364 |
|
// Open sheep driver and remap low memory |
365 |
|
sheep_fd = open("/dev/sheep", 0); |
400 |
|
} |
401 |
|
D(bug("Kernel Data 2 area %ld at %p\n", kernel_area2, kernel_data2)); |
402 |
|
|
403 |
+ |
// Create area for SheepShaver data |
404 |
+ |
if (!SheepMem::Init()) { |
405 |
+ |
sprintf(str, GetString(STR_NO_SHEEP_MEM_AREA_ERR)); |
406 |
+ |
ErrorAlert(str); |
407 |
+ |
PostMessage(B_QUIT_REQUESTED); |
408 |
+ |
return; |
409 |
+ |
} |
410 |
+ |
|
411 |
|
// Create area for Mac RAM |
412 |
|
RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary |
413 |
|
if (RAMSize < 8*1024*1024) { |
461 |
|
XPRAMInit(); |
462 |
|
|
463 |
|
// Set boot volume |
464 |
< |
drive = PrefsFindInt32("bootdrive"); |
464 |
> |
i16 = PrefsFindInt32("bootdrive"); |
465 |
|
XPRAM[0x1378] = i16 >> 8; |
466 |
|
XPRAM[0x1379] = i16 & 0xff; |
467 |
< |
driver = PrefsFindInt32("bootdriver"); |
467 |
> |
i16 = PrefsFindInt32("bootdriver"); |
468 |
|
XPRAM[0x137a] = i16 >> 8; |
469 |
|
XPRAM[0x137b] = i16 & 0xff; |
470 |
|
|
477 |
|
boot_globs[1] = htonl(RAMSize); |
478 |
|
boot_globs[2] = htonl((uint32)-1); // End of bank table |
479 |
|
|
480 |
+ |
// Init thunks |
481 |
+ |
if (!InitThunks()) { |
482 |
+ |
PostMessage(B_QUIT_REQUESTED); |
483 |
+ |
return; |
484 |
+ |
} |
485 |
+ |
|
486 |
|
// Init drivers |
487 |
|
SonyInit(); |
488 |
|
DiskInit(); |
579 |
|
WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR |
580 |
|
WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch |
581 |
|
WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode) |
582 |
+ |
WriteMacInt32(XLM_ZERO_PAGE, SheepMem::ZeroPage()); // Pointer to read-only page with all bits set to 0 |
583 |
|
#if !EMULATED_PPC |
584 |
|
WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator |
585 |
|
WriteMacInt32(XLM_ETHER_INIT, *(uint32 *)InitStreamModule); // DLPI ethernet driver functions |
676 |
|
DiskExit(); |
677 |
|
SonyExit(); |
678 |
|
|
679 |
+ |
// Delete SheepShaver globals |
680 |
+ |
SheepMem::Exit(); |
681 |
+ |
|
682 |
|
// Delete DR Cache area |
683 |
|
if (dr_cache_area >= 0) |
684 |
|
delete_area(dr_cache_area); |
742 |
|
* file_read_error: Cannot read ROM file |
743 |
|
*/ |
744 |
|
|
739 |
– |
// Decode LZSS data |
740 |
– |
static void decode_lzss(const uint8 *src, uint8 *dest, int size) |
741 |
– |
{ |
742 |
– |
char dict[0x1000]; |
743 |
– |
int run_mask = 0, dict_idx = 0xfee; |
744 |
– |
for (;;) { |
745 |
– |
if (run_mask < 0x100) { |
746 |
– |
// Start new run |
747 |
– |
if (--size < 0) |
748 |
– |
break; |
749 |
– |
run_mask = *src++ | 0xff00; |
750 |
– |
} |
751 |
– |
bool bit = run_mask & 1; |
752 |
– |
run_mask >>= 1; |
753 |
– |
if (bit) { |
754 |
– |
// Verbatim copy |
755 |
– |
if (--size < 0) |
756 |
– |
break; |
757 |
– |
int c = *src++; |
758 |
– |
dict[dict_idx++] = c; |
759 |
– |
*dest++ = c; |
760 |
– |
dict_idx &= 0xfff; |
761 |
– |
} else { |
762 |
– |
// Copy from dictionary |
763 |
– |
if (--size < 0) |
764 |
– |
break; |
765 |
– |
int idx = *src++; |
766 |
– |
if (--size < 0) |
767 |
– |
break; |
768 |
– |
int cnt = *src++; |
769 |
– |
idx |= (cnt << 4) & 0xf00; |
770 |
– |
cnt = (cnt & 0x0f) + 3; |
771 |
– |
while (cnt--) { |
772 |
– |
char c = dict[idx++]; |
773 |
– |
dict[dict_idx++] = c; |
774 |
– |
*dest++ = c; |
775 |
– |
idx &= 0xfff; |
776 |
– |
dict_idx &= 0xfff; |
777 |
– |
} |
778 |
– |
} |
779 |
– |
} |
780 |
– |
} |
781 |
– |
|
745 |
|
void SheepShaver::load_rom(void) |
746 |
|
{ |
747 |
|
// Get rom file path from preferences |
770 |
|
|
771 |
|
uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work |
772 |
|
ssize_t actual = file.Read((void *)rom, ROM_SIZE); |
773 |
< |
if (actual == ROM_SIZE) { |
774 |
< |
// Plain ROM image |
775 |
< |
memcpy((void *)ROM_BASE, rom, ROM_SIZE); |
776 |
< |
delete[] rom; |
814 |
< |
} else { |
815 |
< |
if (strncmp((char *)rom, "<CHRP-BOOT>", 11) == 0) { |
816 |
< |
// CHRP compressed ROM image |
817 |
< |
D(bug("CHRP ROM image\n")); |
818 |
< |
uint32 lzss_offset, lzss_size; |
819 |
< |
|
820 |
< |
char *s = strstr((char *)rom, "constant lzss-offset"); |
821 |
< |
if (s == NULL) |
822 |
< |
throw rom_size_error(); |
823 |
< |
s -= 7; |
824 |
< |
if (sscanf(s, "%06lx", &lzss_offset) != 1) |
825 |
< |
throw rom_size_error(); |
826 |
< |
s = strstr((char *)rom, "constant lzss-size"); |
827 |
< |
if (s == NULL) |
828 |
< |
throw rom_size_error(); |
829 |
< |
s -= 7; |
830 |
< |
if (sscanf(s, "%06lx", &lzss_size) != 1) |
831 |
< |
throw rom_size_error(); |
832 |
< |
D(bug("Offset of compressed data: %08lx\n", lzss_offset)); |
833 |
< |
D(bug("Size of compressed data: %08lx\n", lzss_size)); |
834 |
< |
|
835 |
< |
D(bug("Uncompressing ROM...\n")); |
836 |
< |
decode_lzss(rom + lzss_offset, (uint8 *)ROM_BASE, lzss_size); |
837 |
< |
delete[] rom; |
838 |
< |
} else if (rom_size != 4*1024*1024) |
773 |
> |
|
774 |
> |
// Decode Mac ROM |
775 |
> |
if (!DecodeROM(rom, actual)) { |
776 |
> |
if (rom_size != 4*1024*1024) |
777 |
|
throw rom_size_error(); |
778 |
|
else |
779 |
|
throw file_read_error(); |
780 |
|
} |
781 |
+ |
delete[] rom; |
782 |
|
} |
783 |
|
|
784 |
|
|
1267 |
|
|
1268 |
|
|
1269 |
|
/* |
1331 |
– |
* Execute PPC code from EMUL_OP routine (real mode switch) |
1332 |
– |
*/ |
1333 |
– |
|
1334 |
– |
void ExecutePPC(void (*func)()) |
1335 |
– |
{ |
1336 |
– |
RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, func); |
1337 |
– |
M68kRegisters r; |
1338 |
– |
Execute68k((uint32)&desc, &r); |
1339 |
– |
} |
1340 |
– |
|
1341 |
– |
|
1342 |
– |
/* |
1270 |
|
* Quit emulator (must only be called from main thread) |
1271 |
|
*/ |
1272 |
|
|
1321 |
|
|
1322 |
|
void PatchAfterStartup(void) |
1323 |
|
{ |
1324 |
< |
ExecutePPC(VideoInstallAccel); |
1324 |
> |
ExecuteNative(NATIVE_VIDEO_INSTALL_ACCEL); |
1325 |
|
InstallExtFS(); |
1326 |
|
} |
1327 |
|
|
1330 |
|
* NVRAM watchdog thread (saves NVRAM every minute) |
1331 |
|
*/ |
1332 |
|
|
1333 |
< |
static status_t SheepShaver::nvram_func(void *arg) |
1333 |
> |
status_t SheepShaver::nvram_func(void *arg) |
1334 |
|
{ |
1335 |
|
SheepShaver *obj = (SheepShaver *)arg; |
1336 |
|
|
1569 |
|
if (InterruptFlags & INTFLAG_VIA) { |
1570 |
|
ClearInterruptFlag(INTFLAG_VIA); |
1571 |
|
ADBInterrupt(); |
1572 |
< |
ExecutePPC(VideoVBL); |
1572 |
> |
ExecuteNative(NATIVE_VIDEO_VBL); |
1573 |
|
} |
1574 |
|
} |
1575 |
|
#endif |
2064 |
|
} |
2065 |
|
|
2066 |
|
|
2067 |
+ |
/* |
2068 |
+ |
* Helpers to share 32-bit addressable data with MacOS |
2069 |
+ |
*/ |
2070 |
+ |
|
2071 |
+ |
bool SheepMem::Init(void) |
2072 |
+ |
{ |
2073 |
+ |
// Delete old area |
2074 |
+ |
area_id old_sheep_area = find_area(SHEEP_AREA_NAME); |
2075 |
+ |
if (old_sheep_area > 0) |
2076 |
+ |
delete_area(old_sheep_area); |
2077 |
+ |
|
2078 |
+ |
// Create area for SheepShaver data |
2079 |
+ |
base = 0x60000000; |
2080 |
+ |
SheepMemArea = create_area(SHEEP_AREA_NAME, (void **)&base, B_BASE_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); |
2081 |
+ |
if (SheepMemArea < 0) |
2082 |
+ |
return false; |
2083 |
+ |
|
2084 |
+ |
// Create read-only area with all bits set to 0 |
2085 |
+ |
static const uint8 const_zero_page[4096] = {0,}; |
2086 |
+ |
zero_page = const_zero_page; |
2087 |
+ |
|
2088 |
+ |
D(bug("SheepShaver area %ld at %p\n", SheepMemArea, base)); |
2089 |
+ |
top = base + size; |
2090 |
+ |
return true; |
2091 |
+ |
} |
2092 |
+ |
|
2093 |
+ |
void SheepMem::Exit(void) |
2094 |
+ |
{ |
2095 |
+ |
if (SheepMemArea >= 0) |
2096 |
+ |
delete_area(SheepMemArea); |
2097 |
+ |
} |
2098 |
+ |
|
2099 |
+ |
|
2100 |
|
/* |
2101 |
|
* Display error alert |
2102 |
|
*/ |