From 95b59e33153984652db9b5f83301b048527e20d7 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Tue, 11 Apr 2017 20:42:12 +0200 Subject: [PATCH] Support for older systems (64K ROMs). See issue #22. Thanks to @mdanh2002 for submitting the patch. --- libretro/Retro68Runtime.h | 15 +++++++- libretro/relocate.c | 76 +++++++++++++++++++++++++++------------ 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/libretro/Retro68Runtime.h b/libretro/Retro68Runtime.h index b3091be5b7..7dfadb3a5d 100644 --- a/libretro/Retro68Runtime.h +++ b/libretro/Retro68Runtime.h @@ -36,9 +36,22 @@ #define RETRO68_GET_DISPLACEMENT(DISPLACEMENT) \ _RETRO68_GET_DISPLACEMENT(DISPLACEMENT, ) +// Calls to the StripAddress() trap are supposed to make sure addresses are 32-bit clean. +// But this trap doesn’t exist on old ROMs and old system versions, +// so programs built with StripAddress will mysteriously crash. +// Those systems always run in 24-bit mode, so we can just take the lower 24 +// bits of the 32 bit address. +// StripAddress24 must not be used on 32-bit systems, or the resulting crashes +// will be even more mysterious. + +#define StripAddress24(x) ((char*) ((unsigned long)(x) & 0x00FFFFFF)) +#define RETRO68_GET_DISPLACEMENT_STRIP24(DISPLACEMENT) \ + _RETRO68_GET_DISPLACEMENT(DISPLACEMENT, StripAddress24) + +// original StripAddress #define RETRO68_GET_DISPLACEMENT_STRIP(DISPLACEMENT) \ _RETRO68_GET_DISPLACEMENT(DISPLACEMENT, StripAddress) - + #define RETRO68_CALL_UNRELOCATED(FUN,ARGS) \ do { \ long displacement; \ diff --git a/libretro/relocate.c b/libretro/relocate.c index 4fb13b00aa..16a68ae9d7 100644 --- a/libretro/relocate.c +++ b/libretro/relocate.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "Retro68Runtime.h" @@ -98,16 +99,42 @@ static Retro68RelocState relocState __attribute__ ((nocommon)) = { void Retro68Relocate() { + // memory address to retrieve the ROM type (64K or a later ROM) + // see for details http://www.mac.linux-m68k.org/devel/macalmanac.php + short* ROM85 = (short*) 0x028E; + + // figure out which trap is supported + Boolean is128KROM = ((*ROM85) > 0); + Boolean hasSysEnvirons = false; + Boolean hasStripAddr = false; + if (is128KROM) + { + UniversalProcPtr trapSysEnv = GetOSTrapAddress(_SysEnvirons); + UniversalProcPtr trapStripAddr = GetOSTrapAddress(_StripAddress); + UniversalProcPtr trapUnimpl = GetOSTrapAddress(_Unimplemented); + + hasSysEnvirons = (trapSysEnv != trapUnimpl); + hasStripAddr = (trapStripAddr != trapUnimpl); + } + // Figure out the displacement // what is the difference between the addresses in our program code // and an address calculated by PC-relative access? long displacement; - RETRO68_GET_DISPLACEMENT_STRIP(displacement); + + if (hasStripAddr) + { + RETRO68_GET_DISPLACEMENT_STRIP(displacement); + } + else + { + RETRO68_GET_DISPLACEMENT_STRIP24(displacement); + } struct Retro68RelocState *rState = (Retro68RelocState*) ((char*)&relocState + displacement); + // rState now points to the global relocState variable - if(displacement == 0) { if(rState->bssPtr) @@ -126,28 +153,25 @@ void Retro68Relocate() long headerOldVirtualAddress = rState->headerVirtualAddress; struct flat_hdr *header = (struct flat_hdr*) (headerOldVirtualAddress + displacement); uint8_t *base = (uint8_t*) (header+1); - - + // Recover the handle to the code resource by looking at the // longword before the FLT header. The resource templates in Retro68.r store the offset // from the beginning of the code resource there. uint32_t headerOffsetInResource = ((uint32_t*)header)[-1]; - + if(headerOffsetInResource < 4096) // Arbitrary magic number. We expect the offset to be small, just a few header bytes before it. // if it's out of range, assume the longword before the header is not the offset we're looking for. - { - Handle h = RecoverHandle((Ptr) header - headerOffsetInResource); + { + Handle h = RecoverHandle((Ptr) header - headerOffsetInResource); if(MemError() == noErr && h) - { + { // Make sure the code is locked. Only relevant for some code resources. HLock(h); - rState->codeHandle = h; - } + rState->codeHandle = h; + } } - - - + long bss_size = header->bss_end - header->data_end; long n = header->reloc_count; @@ -156,7 +180,7 @@ void Retro68Relocate() long data_end = header->data_end + headerOldVirtualAddress; uint32_t flt_size = (uint32_t) header->data_end; long bss_displacement = 0; - + // Allocate BSS section (uninitialized/zero-initialized global data) if(!rState->bssPtr) { @@ -195,19 +219,25 @@ void Retro68Relocate() addrPtr[0] = (addr >>= 8); //*(uint32_t*)addrPtr = addr; } - + // We're basically done. // Now check whether we're on 68040 or later and need to flush the cache. - SysEnvRec env; - - env.processor = 0; - SysEnvirons(0, &env); - if(env.processor >= env68040) + // only do this if SysEnvirons is available. + // if SysEnvirons is not available, that means we're on an old System or ROM + // and likely not using a 68040, so we won't do this + if (hasSysEnvirons) { - FlushCodeCache(); - } - // accessing globals and calling functions is OK below here. + SysEnvRec env; + env.processor = 0; + SysEnvirons(0, &env); + if(env.processor >= env68040) + { + FlushCodeCache(); + } + } + + // accessing globals and calling functions is OK below here. rState->headerVirtualAddress += displacement; }