Annotation of hatari/src/tos.c, revision 1.1.1.12

1.1       root        1: /*
1.1.1.6   root        2:   Hatari - tos.c
1.1       root        3: 
1.1.1.6   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
1.1.1.6   root        7:   Load TOS image file into ST memory, fix/setup for emulator.
                      8: 
                      9:   The Atari ST TOS needs to be patched to help with emulation. Eg, it references
                     10:   the MMU chip to set memory size. This is patched to the sizes we need without
                     11:   the complicated emulation of hardware which is not needed (as yet). We also
                     12:   patch DMA devices and Hard Drives.
                     13:   NOTE: TOS versions 1.06 and 1.62 were not designed for use on a real STfm.
                     14:   These were for the STe machine ONLY. They access the DMA/Microwire addresses
                     15:   on boot-up which (correctly) cause a bus-error on Hatari as they would in a
                     16:   real STfm. If a user tries to select any of these images we bring up an error.
1.1       root       17: */
1.1.1.12! root       18: const char TOS_rcsid[] = "Hatari $Id: tos.c,v 1.39 2006/03/01 20:46:48 thothy Exp $";
1.1       root       19: 
1.1.1.8   root       20: #include <SDL_endian.h>
1.1.1.4   root       21: 
1.1       root       22: #include "main.h"
1.1.1.9   root       23: #include "configuration.h"
1.1       root       24: #include "file.h"
1.1.1.4   root       25: #include "gemdos.h"
                     26: #include "hdc.h"
1.1.1.10  root       27: #include "ioMem.h"
                     28: #include "log.h"
1.1       root       29: #include "m68000.h"
                     30: #include "memorySnapShot.h"
                     31: #include "stMemory.h"
                     32: #include "tos.h"
                     33: #include "vdi.h"
                     34: 
                     35: 
1.1.1.10  root       36: Uint16 TosVersion;                      /* eg, 0x0100, 0x0102 */
                     37: Uint32 TosAddress, TosSize;             /* Address in ST memory and size of TOS image */
                     38: BOOL bTosImageLoaded = FALSE;           /* Successfully loaded a TOS image? */
                     39: BOOL bRamTosImage;                      /* TRUE if we loaded a RAM TOS image */
                     40: unsigned int ConnectedDriveMask = 0x03; /* Bit mask of connected drives, eg 0x7 is A,B,C */
1.1.1.11  root       41: int nNumDrives = 2;                     /* Number of drives, default is 2 for A: and B: */
1.1.1.10  root       42: 
                     43: 
1.1       root       44: /* Possible TOS file extensions to scan for */
1.1.1.12! root       45: static const char * const pszTosNameExts[] =
1.1.1.6   root       46: {
1.1.1.12! root       47:        ".img",
        !            48:        ".rom",
        !            49:        ".tos",
        !            50:        NULL
1.1       root       51: };
                     52: 
                     53: 
1.1.1.6   root       54: /* Flags that define if a TOS patch should be applied */
                     55: enum
1.1       root       56: {
1.1.1.12! root       57:        TP_ALWAYS,            /* Patch should alway be applied */
        !            58:        TP_ACSI_OFF,          /* Apply patch only if ACSI HD emulation is off */
        !            59:        TP_ANTI_STE           /* Apply patch only if running on plain ST */
1.1.1.6   root       60: };
1.1.1.3   root       61: 
1.1.1.6   root       62: /* This structure is used for patching the TOS ROMs */
1.1.1.7   root       63: typedef struct
1.1       root       64: {
1.1.1.12! root       65:        Uint16 Version;       /* TOS version number */
        !            66:        Sint16 Country;       /* TOS country code: -1 if it does not matter, 0=US, 1=Germany, 2=France, etc. */
        !            67:        const char *pszName;  /* Name of the patch */
        !            68:        int Flags;            /* When should the patch be applied? (see enum above) */
        !            69:        Uint32 Address;       /* Where the patch should be applied */
        !            70:        Uint32 OldData;       /* Expected first 4 old bytes */
        !            71:        Uint32 Size;          /* Length of the patch */
        !            72:        const void *pNewData; /* Pointer to the new bytes */
1.1.1.6   root       73: } TOS_PATCH;
                     74: 
1.1.1.10  root       75: static const char pszDmaBoot[] = "boot from DMA bus";
                     76: static const char pszMouse[] = "working mouse in big screen resolutions";
                     77: static const char pszRomCheck[] = "ROM checksum";
                     78: static const char pszNoSteHw[] = "disable STE hardware access";
1.1.1.12! root       79: static const char pszNoPmmu[] = "disable PMMU access";
1.1.1.6   root       80: 
1.1.1.9   root       81: //static Uint8 pRtsOpcode[] = { 0x4E, 0x75 };  /* 0x4E75 = RTS */
1.1.1.10  root       82: static const Uint8 pNopOpcodes[] = { 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71,
1.1.1.6   root       83:         0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71,
1.1.1.12! root       84:         0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71 };  /* 0x4E71 = NOP */
1.1.1.10  root       85: static const Uint8 pMouseOpcode[] = { 0xD3, 0xC1 };  /* "ADDA.L D1,A1" (instead of "ADDA.W D1,A1") */
                     86: static const Uint8 pRomCheckOpcode[] = { 0x60, 0x00, 0x00, 0x98 };  /* BRA $e00894 */
                     87: static const Uint8 pBraOpcode[] = { 0x60 };  /* 0x60XX = BRA */
1.1       root       88: 
1.1.1.6   root       89: /* The patches for the TOS: */
1.1.1.10  root       90: static const TOS_PATCH TosPatches[] =
1.1.1.6   root       91: {
1.1.1.11  root       92:   { 0x100, -1, pszDmaBoot, TP_ACSI_OFF, 0xFC03D6, 0x610000D0, 4, pNopOpcodes }, /* BSR $FC04A8 */
1.1.1.6   root       93: 
1.1.1.11  root       94:   { 0x102, -1, pszDmaBoot, TP_ACSI_OFF, 0xFC0472, 0x610000E4, 4, pNopOpcodes }, /* BSR.W $FC0558 */
1.1.1.6   root       95:   { 0x102, 0, pszMouse, TP_ALWAYS, 0xFD0030, 0xD2C147F9, 2, pMouseOpcode },
                     96:   { 0x102, 1, pszMouse, TP_ALWAYS, 0xFD008A, 0xD2C147F9, 2, pMouseOpcode },
                     97:   { 0x102, 2, pszMouse, TP_ALWAYS, 0xFD00A8, 0xD2C147F9, 2, pMouseOpcode },
                     98:   { 0x102, 3, pszMouse, TP_ALWAYS, 0xFD0030, 0xD2C147F9, 2, pMouseOpcode },
                     99:   { 0x102, 6, pszMouse, TP_ALWAYS, 0xFCFEF0, 0xD2C147F9, 2, pMouseOpcode },
                    100:   { 0x102, 8, pszMouse, TP_ALWAYS, 0xFCFEFE, 0xD2C147F9, 2, pMouseOpcode },
                    101: 
1.1.1.11  root      102:   { 0x104, -1, pszDmaBoot, TP_ACSI_OFF, 0xFC0466, 0x610000E4, 4, pNopOpcodes }, /* BSR.W $FC054C */
1.1.1.6   root      103: 
1.1.1.11  root      104:   { 0x106, -1, pszDmaBoot, TP_ACSI_OFF, 0xE00576, 0x610000E4, 4, pNopOpcodes }, /* BSR.W $E0065C */
1.1.1.10  root      105: 
1.1.1.11  root      106:   { 0x162, -1, pszDmaBoot, TP_ACSI_OFF, 0xE00576, 0x610000E4, 4, pNopOpcodes }, /* BSR.W $E0065C */
1.1.1.10  root      107: 
1.1.1.11  root      108:   { 0x205, -1, pszDmaBoot, TP_ACSI_OFF, 0xE006AE, 0x610000E4, 4, pNopOpcodes }, /* BSR.W $E00794 */
1.1.1.6   root      109:   /* An unpatched TOS 2.05 only works on STEs, so apply some anti-STE patches... */
1.1.1.11  root      110:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00096, 0x42788900, 4, pNopOpcodes }, /* CLR.W $FFFF8900 */
                    111:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE0009E, 0x31D88924, 4, pNopOpcodes }, /* MOVE.W (A0)+,$FFFF8924 */
                    112:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE000A6, 0x09D10AA9, 28, pNopOpcodes },
                    113:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE003A0, 0x30389200, 4, pNopOpcodes }, /* MOVE.W $ffff9200,D0 */
                    114:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE004EA, 0x61000CBC, 4, pNopOpcodes },
                    115:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00508, 0x61000C9E, 4, pNopOpcodes },
                    116:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE007A0, 0x631E2F3C, 1, pBraOpcode },
                    117:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00928, 0x10388901, 4, pNopOpcodes }, /* MOVE.B $FFFF8901,D0 */
                    118:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00944, 0xB0388901, 4, pNopOpcodes }, /* CMP.B $FFFF8901,D0 */
                    119:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00950, 0x67024601, 1, pBraOpcode },
                    120:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00968, 0x61000722, 4, pNopOpcodes },
                    121:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00CF2, 0x1038820D, 4, pNopOpcodes }, /* MOVE.B $FFFF820D,D0 */
                    122:   { 0x205, -1, pszNoSteHw, TP_ANTI_STE, 0xE00E00, 0x1038820D, 4, pNopOpcodes }, /* MOVE.B $FFFF820D,D0 */
                    123:   { 0x205, 0, pszNoSteHw, TP_ANTI_STE, 0xE03038, 0x31C0860E, 4, pNopOpcodes },
                    124:   { 0x205, 0, pszNoSteHw, TP_ANTI_STE, 0xE034A8, 0x31C0860E, 4, pNopOpcodes },
                    125:   { 0x205, 0, pszNoSteHw, TP_ANTI_STE, 0xE034F6, 0x31E90002, 6, pNopOpcodes },
1.1.1.6   root      126: 
                    127:   /* E007FA  MOVE.L  #$1FFFE,D7  Run checksums on 2xROMs (skip) */
                    128:   /* Checksum is total of TOS ROM image, but get incorrect results */
                    129:   /* as we've changed bytes in the ROM! So, just skip anyway! */
                    130:   { 0x206, -1, pszRomCheck, TP_ALWAYS, 0xE007FA, 0x2E3C0001, 4, pRomCheckOpcode },
1.1.1.11  root      131:   { 0x206, -1, pszDmaBoot, TP_ACSI_OFF, 0xE00898, 0x610000E0, 4, pNopOpcodes }, /* BSR.W $E0097A */
1.1       root      132: 
1.1.1.12! root      133:   { 0x306, -1, pszNoPmmu, TP_ALWAYS, 0xE00068, 0xF0394000, 24, pNopOpcodes },
        !           134:   { 0x306, -1, pszNoPmmu, TP_ALWAYS, 0xE01702, 0xF0394C00, 32, pNopOpcodes },
        !           135: 
1.1.1.6   root      136:   { 0, 0, NULL, 0, 0, 0, 0, NULL }
                    137: };
1.1       root      138: 
                    139: 
                    140: 
1.1.1.6   root      141: /*-----------------------------------------------------------------------*/
                    142: /*
                    143:   Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
                    144: */
                    145: void TOS_MemorySnapShot_Capture(BOOL bSave)
                    146: {
1.1.1.12! root      147:        /* Save/Restore details */
        !           148:        MemorySnapShot_Store(&TosVersion, sizeof(TosVersion));
        !           149:        MemorySnapShot_Store(&TosAddress, sizeof(TosAddress));
        !           150:        MemorySnapShot_Store(&TosSize, sizeof(TosSize));
        !           151:        MemorySnapShot_Store(&ConnectedDriveMask, sizeof(ConnectedDriveMask));
        !           152:        MemorySnapShot_Store(&nNumDrives, sizeof(nNumDrives));
1.1       root      153: }
                    154: 
1.1.1.3   root      155: 
                    156: /*-----------------------------------------------------------------------*/
1.1       root      157: /*
1.1.1.4   root      158:   Patch TOS to skip some TOS setup code which we don't support/need.
1.1.1.12! root      159:  
1.1       root      160:   So, how do we find these addresses when we have no commented source code?
1.1.1.10  root      161:   - For the "Boot from DMA bus" patch:
                    162:     Scan at start of rom for tst.w $482, boot call will be just above it.
1.1       root      163: */
1.1.1.6   root      164: static void TOS_FixRom(void)
1.1       root      165: {
1.1.1.12! root      166:        int nGoodPatches, nBadPatches;
        !           167:        short TosCountry;
        !           168:        const TOS_PATCH *pPatch;
        !           169: 
        !           170:        /* Check for EmuTOS first since we can not patch it */
        !           171:        if (STMemory_ReadLong(TosAddress+0x2c) == 0x45544F53)   /* 0x45544F53 = 'ETOS' */
        !           172:        {
        !           173:                Log_Printf(LOG_DEBUG, "Detected EmuTOS, skipping TOS patches.\n");
        !           174:                return;
        !           175:        }
        !           176: 
        !           177:        /* We also can't patch RAM TOS images (yet) */
        !           178:        if (bRamTosImage)
        !           179:        {
        !           180:                Log_Printf(LOG_DEBUG, "Detected RAM TOS image, skipping TOS patches.\n");
        !           181:                return;
        !           182:        }
        !           183: 
        !           184:        nGoodPatches = nBadPatches = 0;
        !           185:        TosCountry = STMemory_ReadWord(TosAddress+28)>>1;   /* TOS country code */
        !           186:        pPatch = TosPatches;
        !           187: 
        !           188:        /* Apply TOS patches: */
        !           189:        while (pPatch->Version)
        !           190:        {
        !           191:                /* Only apply patches that suit to the actual TOS  version: */
        !           192:                if (pPatch->Version == TosVersion
        !           193:                    && (pPatch->Country == TosCountry || pPatch->Country == -1))
        !           194:                {
        !           195:                        /* Make sure that we really patch the right place by comparing data: */
        !           196:                        if(STMemory_ReadLong(pPatch->Address) == pPatch->OldData)
        !           197:                        {
        !           198:                                /* Only apply the patch if it is really needed: */
        !           199:                                if (pPatch->Flags == TP_ALWAYS || (pPatch->Flags == TP_ACSI_OFF && !ACSI_EMU_ON)
        !           200:                                    || (pPatch->Flags == TP_ANTI_STE && ConfigureParams.System.nMachineType == MACHINE_ST))
        !           201:                                {
        !           202:                                        /* Now we can really apply the patch! */
        !           203:                                        /*fprintf(stderr, "Applying TOS patch '%s'.\n", pPatch->pszName);*/
        !           204:                                        memcpy(&STRam[pPatch->Address], pPatch->pNewData, pPatch->Size);
        !           205:                                        nGoodPatches += 1;
        !           206:                                }
        !           207:                                else
        !           208:                                {
        !           209:                                        /*fprintf(stderr, "Skipped patch '%s'.\n", pPatch->pszName);*/
        !           210:                                }
        !           211:                        }
        !           212:                        else
        !           213:                        {
        !           214:                                Log_Printf(LOG_DEBUG, "Failed to apply TOS patch '%s' at %x (expected %x, found %x).\n",
        !           215:                                           pPatch->pszName, pPatch->Address, pPatch->OldData, STMemory_ReadLong(pPatch->Address));
        !           216:                                nBadPatches += 1;
        !           217:                        }
        !           218:                }
        !           219:                pPatch += 1;
        !           220:        }
1.1.1.3   root      221: 
1.1.1.12! root      222:        Log_Printf(LOG_DEBUG, "Applied %i TOS patches, %i patches failed.\n",
        !           223:                   nGoodPatches, nBadPatches);
1.1.1.6   root      224: }
                    225: 
                    226: 
                    227: /*-----------------------------------------------------------------------*/
                    228: /*
                    229:   Load TOS Rom image file into ST memory space and fix image so can emulate correctly
                    230:   Pre TOS 1.06 are loaded at 0xFC0000 with later ones at 0xE00000
                    231: */
                    232: int TOS_LoadImage(void)
                    233: {
1.1.1.12! root      234:        Uint8 *pTosFile = NULL;
        !           235:        long nFileSize;
1.1.1.6   root      236: 
1.1.1.12! root      237:        bTosImageLoaded = FALSE;
1.1.1.6   root      238: 
1.1.1.12! root      239:        /* Load TOS image into memory so we can check it's vesion */
        !           240:        TosVersion = 0;
        !           241:        pTosFile = File_Read(ConfigureParams.Rom.szTosImageFileName, NULL, &nFileSize, pszTosNameExts);
        !           242: 
        !           243:        if (!pTosFile || nFileSize <= 0)
        !           244:        {
        !           245:                Log_AlertDlg(LOG_FATAL, "Can not load TOS file:\n'%s'", ConfigureParams.Rom.szTosImageFileName);
        !           246:                return -1;
        !           247:        }
        !           248: 
        !           249:        TosSize = nFileSize;
        !           250: 
        !           251:        /* Check for RAM TOS images first: */
        !           252:        if (SDL_SwapBE32(*(Uint32 *)pTosFile) == 0x46FC2700)
        !           253:        {
        !           254:                Log_Printf(LOG_WARN, "Detected a RAM TOS - this will probably not work very well!\n");
        !           255:                /* RAM TOS images have a 256 bytes loader function before the real image
        !           256:                 * starts, so we simply skip the first 256 bytes here: */
        !           257:                TosSize -= 0x100;
        !           258:                memmove(pTosFile, pTosFile + 0x100, TosSize);
        !           259:                bRamTosImage = TRUE;
        !           260:        }
        !           261:        else
        !           262:        {
        !           263:                bRamTosImage = FALSE;
        !           264:        }
        !           265: 
        !           266:        /* Now, look at start of image to find Version number and address */
        !           267:        TosVersion = SDL_SwapBE16(*(Uint16 *)&pTosFile[2]);
        !           268:        TosAddress = SDL_SwapBE32(*(Uint32 *)&pTosFile[8]);
        !           269: 
        !           270:        /* Check for reasonable TOS version: */
        !           271:        if (TosVersion<0x100 || TosVersion>0x500 || TosSize>1024*1024L
        !           272:            || (!bRamTosImage && TosAddress!=0xe00000 && TosAddress!=0xfc0000))
        !           273:        {
        !           274:                Log_AlertDlg(LOG_FATAL, "Your TOS image seems not to be a valid TOS ROM file!\n"
        !           275:                             "(TOS version %x, address $%x)", TosVersion, TosAddress);
        !           276:                return -2;
        !           277:        }
        !           278: 
        !           279:        /* TOSes 1.06 and 1.62 are for the STE ONLY and so don't run on a real ST. */
        !           280:        /* They access illegal memory addresses which don't exist on a real machine and cause the OS */
        !           281:        /* to lock up. So, if user selects one of these, switch to STE mode. */
        !           282:        if ((TosVersion == 0x0106 || TosVersion == 0x0162) && ConfigureParams.System.nMachineType != MACHINE_STE)
        !           283:        {
        !           284:                Log_AlertDlg(LOG_INFO, "TOS versions 1.06 and 1.62\nare NOT valid ST ROM images.\n"
        !           285:                             " => Switching to STE mode now.\n");
        !           286:                IoMem_UnInit();
        !           287:                ConfigureParams.System.nMachineType = MACHINE_STE;
        !           288:                IoMem_Init();
        !           289:        }
        !           290: 
        !           291:        /* Copy loaded image into ST memory */
        !           292:        memcpy(STRam+TosAddress, pTosFile, TosSize);
        !           293: 
        !           294:        Log_Printf(LOG_DEBUG, "Loaded TOS version %i.%c%c, starting at $%x, "
        !           295:                   "country code = %i, %s\n", TosVersion>>8, '0'+((TosVersion>>4)&0x0f),
        !           296:                   '0'+(TosVersion&0x0f), TosAddress, STMemory_ReadWord(TosAddress+28)>>1,
        !           297:                   (STMemory_ReadWord(TosAddress+28)&1)?"PAL":"NTSC");
        !           298: 
        !           299:        /* Are we allowed VDI under this TOS? */
        !           300:        if (TosVersion == 0x0100 && bUseVDIRes)
        !           301:        {
        !           302:                /* Warn user */
        !           303:                Log_AlertDlg(LOG_WARN, "To use GEM extended resolutions, you must select a TOS >= 1.02.");
        !           304:                /* And select non VDI */
        !           305:                bUseVDIRes = ConfigureParams.Screen.bUseExtVdiResolutions = FALSE;
        !           306:        }
        !           307: 
        !           308:        /* Fix TOS image, modify code for emulation */
        !           309:        TOS_FixRom();
        !           310: 
        !           311:        /* Set connected devices, memory configuration, etc. */
        !           312:        STMemory_SetDefaultConfig();
1.1.1.6   root      313: 
1.1.1.12! root      314:        /* and free loaded image */
        !           315:        free(pTosFile);
1.1.1.6   root      316: 
1.1.1.12! root      317:        bTosImageLoaded = TRUE;
1.1.1.6   root      318: 
1.1.1.12! root      319:        return 0;
1.1       root      320: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.