static void cpuFrame2(UWO vector_offset, ULO pc) { // save inst address cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(cpuGetOriginalPC(), cpuGetAReg(7)); cpuFrame4Words(0x2000, vector_offset, pc); }
static BYT fhfileWrite(ULO index) { ULO dest = memoryReadLong(cpuGetAReg(1) + 40); ULO offset = memoryReadLong(cpuGetAReg(1) + 44); ULO length = memoryReadLong(cpuGetAReg(1) + 36); if (fhfile_devs[index].readonly || ((offset + length) > fhfile_devs[index].size)) { return -3; } fhfileSetLed(true); #ifdef RETRO_PLATFORM if(RP.GetHeadlessMode()) RP.PostHardDriveLED(index, true, true); #endif fseek(fhfile_devs[index].F, offset, SEEK_SET); fwrite(memoryAddressToPtr(dest),1, length, fhfile_devs[index].F); memoryWriteLong(length, cpuGetAReg(1) + 32); fhfileSetLed(false); #ifdef RETRO_PLATFORM if(RP.GetHeadlessMode()) RP.PostHardDriveLED(index, false, true); #endif return 0; }
uint16_t FlushCodeCacheRange() { // FUNCTION FlushCodeCacheRange (address: UNIV Ptr; count: LongInt): OSErr; uint32_t address = cpuGetAReg(0); uint32_t count = cpuGetAReg(1); Log(" FlushCodeCacheRange(%08x, %08x)\n", address, count); return 0; }
static void cpuFrameGroup1(UWO vector_offset, ULO pcPtr) { // save PC cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(pcPtr, cpuGetAReg(7)); // save SR cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord((UWO)cpuGetSR(), cpuGetAReg(7)); }
void cpuSetUpInterrupt(ULO new_interrupt_level) { UWO vector_offset = (UWO) (0x60 + new_interrupt_level*4); ULO vector_address = memoryReadLong(cpuGetVbr() + vector_offset); cpuActivateSSP(); // Switch to using ssp or msp. Loads a7 and preserves usp if we came from user-mode. cpuStackFrameGenerate(vector_offset, cpuGetPC()); // This will end up on msp if master is enabled, or on the ssp/isp if not. cpuSetSR(cpuGetSR() & 0x38ff); // Clear interrupt level cpuSetSR(cpuGetSR() | 0x2000); // Set supervisor mode cpuSetSR(cpuGetSR() | (UWO)(new_interrupt_level << 8)); // Set interrupt level #ifdef CPU_INSTRUCTION_LOGGING cpuCallInterruptLoggingFunc(new_interrupt_level, vector_address); #endif if (cpuGetModelMajor() >= 2 && cpuGetModelMajor() < 6) { if (cpuGetFlagMaster()) { // If the cpu was in master mode, preserve msp, and switch to using ssp (isp) in a7. ULO oldA7 = cpuGetAReg(7); cpuSetMspDirect(oldA7); cpuSetAReg(7, cpuGetSspDirect()); cpuFrame1(vector_offset, cpuGetPC()); // Make the throwaway frame on ssp/isp cpuSetSR(cpuGetSR() & 0xefff); // Clear master bit } } cpuInitializeFromNewPC(vector_address); cpuSetStop(FALSE); cpuSetRaiseInterrupt(FALSE); }
uint32_t GetHandleSize(uint16_t trap) { /* * on entry: * A0 handle * * on exit: * D0 size (32-bit) or error code * */ /* * The trap dispatcher sets the condition codes before returning * from a trap by testing the low-order word of register D0 with * a TST.W instruction. Because the block size returned in D0 by * _GetHandleSize is a full 32-bit long word, the word-length * test sets the condition codes incorrectly in this case. To * branch on the contents of D0, use your own TST.L instruction * on return from the trap to test the full 32 bits of the register. */ uint32_t hh = cpuGetAReg(0); Log("%04x GetHandleSize(%08x)\n", trap, hh); if (hh == 0) return SetMemError(MacOS::nilHandleErr); // ???? auto iter = HandleMap.find(hh); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); return iter->second.size; }
uint16_t EmptyHandle(uint16_t trap) { /* * on entry: * A0 Handle to be disposed of * * on exit: * D0 Result code * */ uint32_t hh = cpuGetAReg(0); Log("%04x EmptyHandle(%08x)\n", trap, hh); auto iter = HandleMap.find(hh); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto &info = iter->second; if (info.address == 0) return SetMemError(0); if (info.locked) return SetMemError(MacOS::memLockedErr); // ? void *address = Memory + info.address; mplite_free(&pool, address); info.address = 0; info.size = 0; memoryWriteLong(0, hh); return 0; }
uint16_t PtrToHand(uint16_t trap) { /* * on entry: * A0 source Pointer * D0 size * * on exit: * A0 destination pointer * D0 Result code * */ uint32_t mcptr = cpuGetAReg(0); uint32_t size = cpuGetDReg(0); Log("%04x PtrToHand(%08x, %08x)\n", trap, mcptr, size); uint32_t destHandle; uint32_t destPtr; uint32_t d0 = Native::NewHandle(size, false, destHandle, destPtr); if (d0 == 0) { std::memmove(memoryPointer(destPtr), memoryPointer(mcptr), size); } cpuSetAReg(0, destHandle); return d0; // SetMemError called by Native::NewHandle. }
uint16_t HandleZone(uint16_t trap) { // FUNCTION HandleZone (h: Handle): THz; /* * on entry: * A0 Handle whose zone is to be found * * on exit: * A0 Pointer to handle’s heap zone * D0 Result code * */ uint32_t h = cpuGetAReg(0); Log("%04x HandleZone(%08x)\n", trap, h); if (HandleMap.find(h) == HandleMap.end()) { cpuSetAReg(0, 0); return SetMemError(MacOS::memWZErr); } cpuSetAReg(0, 0); return SetMemError(0); }
uint16_t SetPtrSize(uint16_t trap) { /* * on entry: * A0 pointer * D0 new size * * on exit: * D0 Result code * */ uint32_t mcptr = cpuGetAReg(0); uint32_t newSize = cpuGetDReg(0); Log("%08x SetPtrSize(%08x, %08x)\n", trap, mcptr, newSize); auto iter = PtrMap.find(mcptr); if (iter == PtrMap.end()) return SetMemError(MacOS::memWZErr); uint8_t *ptr = mcptr + Memory; if (mplite_resize(&pool, ptr, mplite_roundup(&pool, newSize)) < 0) { return SetMemError(MacOS::memFullErr); } // update the size. iter->second = newSize; return SetMemError(0); }
void fhfileDiag(void) { fhfile_configdev = cpuGetAReg(3); memoryDmemSetLongNoCounter(FHFILE_MAX_DEVICES, 4088); memoryDmemSetLongNoCounter(fhfile_configdev, 4092); cpuSetDReg(0, 1); }
uint16_t HandToHand(uint16_t trap) { /* * on entry: * A0 source Handle * * on exit: * A0 destination Handle * D0 Result code * */ uint32_t srcHandle = cpuGetAReg(0); Log("%04x HandToHand(%08x)\n", trap, srcHandle); auto iter = HandleMap.find(srcHandle); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto const info = iter->second; uint32_t destHandle; uint32_t destPtr; uint32_t d0 = Native::NewHandle(info.size, false, destHandle, destPtr); if (d0 == 0) { std::memmove(memoryPointer(destPtr), memoryPointer(info.address), info.size); } cpuSetAReg(0, destHandle); return d0; // SetMemError called by Native::NewHandle. }
uint16_t HSetState(uint16_t trap) { /* * on entry: * A0 Handle * D0 flags * * on exit: * D0 flag byte * */ uint32_t hh = cpuGetAReg(0); uint16_t flags = cpuGetDReg(0); Log("%04x HSetState(%08x, %04x)\n", trap, hh, flags); auto iter = HandleMap.find(hh); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto &info = iter->second; info.resource = (flags & (1 << 5)); info.purgeable = (flags & (1 << 6)); info.locked = (flags & (1 << 7)); return SetMemError(0); }
uint16_t PtrAndHand(uint16_t trap) { // FUNCTION PtrAndHand (pntr: Ptr; hndl: Handle; size: LongInt): OSErr; /* * on entry: * A0 source Pointer * A1 dest Handle * D0 number of bytes to concatenate * * on exit: * A0 destination Handle * D0 Result code * */ uint32_t ptr = cpuGetAReg(0); uint32_t handle = cpuGetAReg(1); uint32_t size = cpuGetDReg(0); Log("%04x PtrAndHand(%08x, %08x, %08x)\n", trap, ptr, handle, size); cpuSetAReg(0, handle); uint32_t oldSize = 0; uint32_t d0; d0 = Native::GetHandleSize(handle, oldSize); if (d0) return d0; if ((uint64_t)oldSize + (uint64_t)size > UINT32_MAX) return SetMemError(MacOS::memFullErr); d0 = Native::SetHandleSize(handle, oldSize + size); if (d0) return d0; auto iter = HandleMap.find(handle); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto const info = iter->second; std::memmove(memoryPointer(info.address + oldSize), memoryPointer(ptr), size); return SetMemError(0); }
/// <summary> /// Returns the interrupt stack pointer. ssp is used as isp. /// </summary> ULO cpuGetIspAutoMap(void) { if (cpuGetFlagSupervisor() && !cpuGetFlagMaster()) { return cpuGetAReg(7); } return cpuGetSspDirect(); }
/* * ReallocHandle (h: Handle; logicalSize: Size); * * ReallocHandle allocates a new relocatable block with a logical * size of logicalSize bytes. It then updates handle h by setting * its master pointer to point to the new block. The main use of * this procedure is to reallocate space for a block that has * been purged. Normally h is an empty handle, but it need not * be: If it points to an existing block, that block is released * before the new block is created. * * In case of an error, no new block is allocated and handle h is * left unchanged. */ uint16_t ReallocHandle(uint16_t trap) { /* * on entry: * A0 Handle to be disposed of * D0 Logical Size * * on exit: * D0 Result code * */ uint32_t hh = cpuGetAReg(0); uint32_t logicalSize = cpuGetDReg(0); Log("%04x ReallocHandle(%08x, %08x)\n", trap, hh, logicalSize); return Native::ReallocHandle(hh, logicalSize); #if 0 auto iter = HandleMap.find(hh); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); auto& info = iter->second; if (info.locked) return SetMemError(MacOS::memLockedErr); if (info.address) { void *address = Memory + info.address; mplite_free(&pool, address); info.address = 0; info.size = 0; memoryWriteLong(0, hh); } // allocate a new block... if (logicalSize == 0) return SetMemError(0); void *address = mplite_malloc(&pool, logicalSize); if (!address) return SetMemError(MacOS::memFullErr); uint32_t mcptr = (uint8_t *)address - Memory; info.size = logicalSize; info.address = mcptr; memoryWriteLong(mcptr, hh); // lock? clear purged flag? return 0; #endif }
void ftrap_access(uint16_t trap) { // open a file, rename a file, or delete a file. std::string sname; uint32_t d0; uint32_t sp = cpuGetAReg(7); // hmmm not sure if 3 or 4 parameters. uint32_t name = memoryReadLong(sp + 4); uint32_t op = memoryReadLong(sp + 8); uint32_t parm = memoryReadLong(sp + 12); Log("%04x Access(%08x, %04x, %08x)\n", trap, name, op, parm); switch (op) { case kF_OPEN: d0 = ftrap_open(name, parm); break; case kF_DELETE: d0 = ftrap_delete(name); break; case kF_RENAME: d0 = ftrap_rename(name, parm); break; case kF_GTABINFO: d0 = ftrap_get_tab_info(name, parm); break; case kF_STABINFO: d0 = ftrap_set_tab_info(name, parm); break; case kF_GFONTINFO: d0 = ftrap_get_font_info(name, parm); break; case kF_SFONTINFO: d0 = ftrap_set_font_info(name, parm); break; default: d0 = 0x40000000 | kEINVAL; fprintf(stderr, "faccess - unsupported op %04x\n", op); exit(1); } cpuSetDReg(0, d0); }
static void fhfileBeginIO(void) { BYT error = 0; ULO unit = memoryReadLong(cpuGetAReg(1) + 24); UWO cmd = memoryReadWord(cpuGetAReg(1) + 28); switch (cmd) { case 2: error = fhfileRead(unit); break; case 3: case 11: error = fhfileWrite(unit); break; case 18: fhfileGetDriveType(unit); break; case 19: fhfileGetNumberOfTracks(unit); break; case 15: fhfileWriteProt(unit); break; case 4: case 5: case 9: case 10: case 12: case 13: case 14: case 20: case 21: fhfileIgnore(unit); break; default: error = -3; cpuSetDReg(0, 0); break; } memoryWriteByte(5, cpuGetAReg(1) + 8); /* ln_type */ memoryWriteByte(error, cpuGetAReg(1) + 31); /* ln_error */ }
uint16_t SysEnvirons(uint16_t trap) { // FUNCTION SysEnvirons (versionRequested: Integer; // VAR theWorld: SysEnvRec): OSErr; /* * on entry: * D0 Version requested * A0 SysEnvRec pointer * * on exit: * D0 Result code * */ enum { /* SysEnvRec */ _environsVersion = 0, _machineType = 2, _systemVersion = 4, _processor = 6, _hasFPU = 8, _hasColorQD = 9, _keyBoardType = 10, _atDrvrVersNum = 12, _sysVRefNum = 14, }; uint16_t versionRequested = cpuGetDReg(0); uint32_t theWorld = cpuGetAReg(0); Log("%04x SysEnvirons(%04x, %08x)\n", trap, versionRequested, theWorld); memoryWriteWord(2, theWorld + _environsVersion); // negative version. if (versionRequested >= 0x8000) return MacOS::envBadVers; if (versionRequested > 2) return MacOS::envVersTooBig; memoryWriteWord(0, theWorld + _machineType); // 0 = unknown model newer than the IIci (v1) or IIfx (v2) memoryWriteWord(1 + cpuGetModelMajor(), theWorld + _processor); memoryWriteWord(0x0700, theWorld + _systemVersion); // system 7 memoryWriteWord(0, theWorld + _hasFPU); memoryWriteWord(0, theWorld + _hasColorQD); memoryWriteWord(5, theWorld + _keyBoardType); // standard adb I guess memoryWriteWord(0, theWorld + _atDrvrVersNum); // no appletalk memoryWriteWord(-1, theWorld + _sysVRefNum); // System folder # return 0; }
uint16_t SwapDataCache() { // FUNCTION SwapDataCache (cacheEnable: Boolean): Boolean; // boolean value sent/returned via a0. // c.f. mpw DumpObj -m SWAPDATACACHE Interface.o uint16_t cacheEnable = cpuGetAReg(0) & 0xff; Log(" SwapDataCache(%02x)\n", cacheEnable); cpuSetAReg(0, 0); return 0; }
static void cpuFrameGroup2(UWO vector_offset, ULO pcPtr) { // save PC cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(pcPtr, cpuGetAReg(7)); // save SR cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord((UWO)cpuGetSR(), cpuGetAReg(7)); // fault address, skip ireg cpuSetAReg(7, cpuGetAReg(7) - 6); memoryWriteLong(memory_fault_address, cpuGetAReg(7)); cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteLong(memory_fault_read << 4, cpuGetAReg(7)); }
uint16_t BlockMove(uint16_t trap) { // also implements BlockMoveData. // BlockMove will flush caches, BlockMoveData will not. /* * on entry: * A0 Pointer to source * A1 Pointer to destination * D0 Number of bytes to copy * * on exit: * A0 Address of the new block or NIL * D0 Result code * */ uint32_t source = cpuGetAReg(0); uint32_t dest = cpuGetAReg(1); uint32_t count = cpuGetDReg(0); Log("%04x BlockMove(%08x, %08x, %08x)\n", trap, source, dest, count); // TODO -- 32-bit clean? // TODO -- verify within MemorySize? #if 0 if (source == 0 || dest == 0 || count == 0) return 0; #endif std::memmove(Memory + dest, Memory + source, count); return 0; }
static void fhfileOpen(void) { if (cpuGetDReg(0) < FHFILE_MAX_DEVICES) { memoryWriteByte(7, cpuGetAReg(1) + 8); /* ln_type (NT_REPLYMSG) */ memoryWriteByte(0, cpuGetAReg(1) + 31); /* io_error */ memoryWriteLong(cpuGetDReg(0), cpuGetAReg(1) + 24); /* io_unit */ memoryWriteLong(memoryReadLong(cpuGetAReg(6) + 32) + 1, cpuGetAReg(6) + 32); /* LIB_OPENCNT */ cpuSetDReg(0, 0); /* ? */ } else { memoryWriteLong(-1, cpuGetAReg(1) + 20); memoryWriteByte(-1, cpuGetAReg(1) + 31); /* io_error */ cpuSetDReg(0, -1); /* ? */ } }
uint16_t DisposeHandle(uint16_t trap) { /* * on entry: * A0 Handle to be disposed of * * on exit: * D0 Result code * */ uint32_t hh = cpuGetAReg(0); Log("%04x DisposeHandle(%08x)\n", trap, hh); return Native::DisposeHandle(hh); }
uint16_t SetApplLimit(uint16_t trap) { // PROCEDURE SetApplLimit (zoneLimit: Ptr); /* * on entry * A0 Pointer to desired new zone limit * * on exit * D0 Result code */ uint32_t zoneLimit = cpuGetAReg(0); Log("%04x SetApplLimit(%08x)\n", trap, zoneLimit); return 0; }
uint16_t SetZone(uint16_t trap) { // PROCEDURE SetZone (hz: THz); /* * on entry: * A0 Pointer to new current heap zone * * on exit: * D0 Result code */ uint32_t THz = cpuGetAReg(0); Log("%04x SetZone(%08x)\n", trap, THz); return 0; }
uint32_t RecoverHandle(uint16_t trap) { // FUNCTION RecoverHandle (p: Ptr): Handle; /* * on entry: * A0 Master pointer * * on exit: * A0 Handle to master pointer’s relocatable block * D0 Unchanged * */ uint32_t p = cpuGetAReg(0); uint32_t hh = 0; Log("%04x RecoverHandle(%08x)\n", trap, p); uint16_t error = MacOS::memBCErr; for (const auto kv : HandleMap) { const HandleInfo &info = kv.second; if (!info.address) continue; uint32_t begin = info.address; uint32_t end = info.address + info.size; if (!info.size) end++; if (p >= begin && p < end) { hh = kv.first; error = MacOS::noErr; break; } } SetMemError(error); cpuSetAReg(0, hh); // return d0 register unchanged. return cpuGetDReg(0); }
static void cpuFrame4Words(UWO frame_code, UWO vector_offset, ULO pc) { // save vector_offset word cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord(frame_code | vector_offset, cpuGetAReg(7)); // save PC cpuSetAReg(7, cpuGetAReg(7) - 4); memoryWriteLong(pc, cpuGetAReg(7)); // save SR cpuSetAReg(7, cpuGetAReg(7) - 2); memoryWriteWord((UWO)cpuGetSR(), cpuGetAReg(7)); }
uint16_t HGetState(uint16_t trap) { /* * on entry: * A0 Handle * * on exit: * D0 flag byte * */ unsigned flags = 0; uint32_t hh = cpuGetAReg(0); Log("%04x HGetState(%08x)\n", trap, hh); auto iter = HandleMap.find(hh); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); /* * flag bits: * 0-4: reserved * 5: is a resource * 6: set if purgeable * 7: set if locked */ const auto &info = iter->second; // resouce not yet supported... // would need extra field and support in RM:: when // creating. // see HSetRBit, HClrRBit if (info.resource) flags |= (1 << 5); if (info.purgeable) flags |= (1 << 6); if (info.locked) flags |= (1 << 7); SetMemError(0); return flags; }
uint32_t GetPtrSize(uint16_t trap) { /* * on entry: * A0 pointer * * on exit: * D0 size (32-bit) or error code * */ uint32_t mcptr = cpuGetAReg(0); Log("%08x GetPtrSize(%08x)\n", trap, mcptr); auto iter = PtrMap.find(mcptr); if (iter == PtrMap.end()) return SetMemError(MacOS::memWZErr); return iter->second; }