Annotation of hatari/src/ioMem.c, revision 1.1.1.14

1.1       root        1: /*
                      2:   Hatari - ioMem.c
                      3: 
1.1.1.10  root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
                      7:   This is where we intercept read/writes to/from the hardware. The ST's memory
                      8:   is nicely split into four main parts - the bottom area of RAM is for user
                      9:   programs. This is followed by a large area which causes a Bus Error. After
                     10:   this is the ROM addresses for TOS and finally an area for hardware mapping.
                     11:   To gain speed any address in the user area can simply read/write, but anything
                     12:   above this range needs to be checked for validity and sent to the various
                     13:   handlers.
                     14:   A big problem for ST emulation is the use of the hardware registers. These
                     15:   often consist of an 'odd' byte in memory and is usually addressed as a single
                     16:   byte. A number of applications, however, write to the address using a word or
                     17:   even long word. So we have a list of handlers that take care of each address
                     18:   that has to be intercepted. Eg, a long write to a PSG register (which access
                     19:   two registers) will write the long into IO memory space and then call the two
                     20:   handlers which read off the bytes for each register.
                     21:   This means that any access to any hardware register in such a way will work
                     22:   correctly - it certainly fixes a lot of bugs and means writing just one
                     23:   routine for each hardware register we mean to intercept! Phew!
                     24:   You have also to take into consideration that some hardware registers are
                     25:   bigger than 1 byte (there are also word and longword registers) and that
                     26:   a lot of addresses in between can cause a bus error - so it's not so easy
                     27:   to cope with all type of handlers in a straight forward way.
                     28:   Also note the 'mirror' (or shadow) registers of the PSG - this is used by most
                     29:   games.
                     30: */
1.1.1.6   root       31: const char IoMem_fileid[] = "Hatari ioMem.c : " __DATE__ " " __TIME__;
1.1       root       32: 
                     33: #include "main.h"
                     34: #include "configuration.h"
                     35: #include "ioMem.h"
                     36: #include "ioMemTables.h"
1.1.1.8   root       37: #include "memorySnapShot.h"
1.1       root       38: #include "m68000.h"
1.1.1.3   root       39: #include "sysdeps.h"
1.1.1.13  root       40: #include "newcpu.h"
1.1       root       41: 
                     42: 
1.1.1.14! root       43: static void (*pInterceptReadTable[0x8000])(void);      /* Table with read access handlers */
        !            44: static void (*pInterceptWriteTable[0x8000])(void);     /* Table with write access handlers */
1.1       root       45: 
1.1.1.14! root       46: int nIoMemAccessSize;                                  /* Set to 1, 2 or 4 according to byte, word or long word access */
        !            47: Uint32 IoAccessFullAddress;                            /* Store the complete 32 bit address received in the IoMem_xxx() handler */
        !            48:                                                        /* (this is the address to write on the stack in case of a bus error) */
        !            49: Uint32 IoAccessBaseAddress;                            /* Stores the base address of the IO mem access (masked on 24 bits) */
        !            50: Uint32 IoAccessCurrentAddress;                         /* Current byte address while handling WORD and LONG accesses (masked on 24 bits) */
        !            51: static int nBusErrorAccesses;                          /* Needed to count bus error accesses */
1.1       root       52: 
1.1.1.13  root       53: 
                     54: /*
                     55:   Heuristics for better cycle accuracy when "cycle exact mode" is not used
                     56: 
                     57:   Some instructions can do several IO accesses that will be seen as several independent accesses,
                     58:   instead of one whole word or long word access as in the size of the instruction.
                     59:   For example :
                     60:     - movep.w and move.l will do 2 or 4 BYTE accesses (and not 1 WORD or LONG WORD access)
                     61:     - move.l will do 2 WORD accesses (and not 1 LONG WORD, because ST's bus is 16 bit)
                     62: 
                     63:   So, when a BYTE access is made, we need to know if it comes from an instruction where size=byte
                     64:   or if it comes from a word or long word instruction.
                     65: 
                     66:   In order to emulate correct read/write cycles when IO regs are accessed this way, we need to
                     67:   keep track of how many accesses were made by the same instruction.
                     68:   This will be used when CPU runs in "prefetch mode" and we try to approximate internal cycles
                     69:   (see cycles.c for heuristics using this).
                     70: 
                     71:   When CPU runs in "cycle exact mode", this is not used because the internal cycles will be computed
                     72:   precisely at the CPU emulation level.
                     73: */
                     74: static Uint64  IoAccessInstrPrevClock;
                     75: int            IoAccessInstrCount;                     /* Number of the accesses made in the current instruction (1..4) */
                     76:                                                        /* 0 means no multiple accesses in the current instruction */
                     77: 
                     78: 
1.1.1.8   root       79: /* Falcon bus mode (Falcon STe compatible bus or Falcon only bus) */
                     80: static enum {
                     81:        STE_BUS_COMPATIBLE,
                     82:        FALCON_ONLY_BUS
                     83: } falconBusMode;
                     84: 
                     85: /*-----------------------------------------------------------------------*/
                     86: /**
                     87:  * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
                     88:  */
                     89: void IoMem_MemorySnapShot_Capture(bool bSave)
                     90: {
                     91:        /* Save/Restore details */
                     92:        MemorySnapShot_Store(&falconBusMode, sizeof(falconBusMode));
                     93: }
1.1       root       94: 
                     95: /*-----------------------------------------------------------------------*/
1.1.1.3   root       96: /**
                     97:  * Fill a region with bus error handlers.
                     98:  */
1.1       root       99: static void IoMem_SetBusErrorRegion(Uint32 startaddr, Uint32 endaddr)
                    100: {
                    101:        Uint32 a;
                    102: 
                    103:        for (a = startaddr; a <= endaddr; a++)
                    104:        {
                    105:                if (a & 1)
                    106:                {
                    107:                        pInterceptReadTable[a - 0xff8000] = IoMem_BusErrorOddReadAccess;     /* For 'read' */
                    108:                        pInterceptWriteTable[a - 0xff8000] = IoMem_BusErrorOddWriteAccess;   /* and 'write' */
                    109:                }
                    110:                else
                    111:                {
                    112:                        pInterceptReadTable[a - 0xff8000] = IoMem_BusErrorEvenReadAccess;    /* For 'read' */
                    113:                        pInterceptWriteTable[a - 0xff8000] = IoMem_BusErrorEvenWriteAccess;  /* and 'write' */
                    114:                }
                    115:        }
                    116: }
                    117: 
                    118: 
1.1.1.13  root      119: /**
                    120:  * Fill a region with void handlers.
                    121:  */
                    122: static void IoMem_SetVoidRegion(Uint32 startaddr, Uint32 endaddr)
                    123: {
                    124:        Uint32 addr;
                    125: 
                    126:        for (addr = startaddr; addr <= endaddr; addr++)
                    127:        {
                    128:                pInterceptReadTable[addr - 0xff8000] = IoMem_VoidRead;
                    129:                pInterceptWriteTable[addr - 0xff8000] = IoMem_VoidWrite;
                    130:        }
                    131: }
                    132: 
                    133: 
                    134: /**
                    135:  * Normal ST has two address which don't generate a bus error when
                    136:  * compared to the Mega-ST. Mark them as void handlers here.
                    137:  */
                    138: static void IoMem_FixVoidAccessForST(void)
                    139: {
                    140:        IoMem_SetVoidRegion(0xff820f, 0xff820f);
                    141:        IoMem_SetVoidRegion(0xff860f, 0xff860f);
                    142: }
                    143: 
                    144: /**
                    145:  * Mega-ST has slightly different behavior with bus errors compared to
                    146:  * the normal ST. Here we fix up the table accordingly.
                    147:  */
                    148: static void IoMem_FixVoidAccessForMegaST(void)
                    149: {
                    150:        int i;
                    151:        Uint32 no_be_addrs[] =
                    152:        {
                    153:                0xff8200, 0xff8202, 0xff8204, 0xff8206, 0xff8208,
                    154:                0xff820c, 0xff8608, 0xff860a, 0xff860c, 0
                    155:        };
                    156:        Uint32 no_be_regions[][2] =
                    157:        {
                    158:                { 0xff8000, 0xff8000 },
                    159:                { 0xff8002, 0xff800d },
                    160:                { 0xff8a3e, 0xff8a3f },
                    161:                { 0, 0 }
                    162:        };
                    163: 
                    164:        for (i = 0; no_be_addrs[i] != 0; i++)
                    165:        {
                    166:                IoMem_SetVoidRegion(no_be_addrs[i], no_be_addrs[i]);
                    167:        }
                    168:        for (i = 0; no_be_regions[i][0] != 0; i++)
                    169:        {
                    170:                IoMem_SetVoidRegion(no_be_regions[i][0], no_be_regions[i][1]);
                    171:        }
                    172: }
                    173: 
                    174: 
                    175: /**
                    176:  * Fix up the IO memory access table for the Mega STE.
                    177:  */
                    178: static void IoMem_FixAccessForMegaSTE(void)
                    179: {
                    180:        int addr;
                    181: 
                    182:        /* Mega-STE has an additional Cache/CPU control register compared to the normal STE. */
                    183:        pInterceptReadTable[0xff8e21 - 0xff8000] = IoMem_ReadWithoutInterception;
                    184:        pInterceptWriteTable[0xff8e21 - 0xff8000] = IoMemTabMegaSTE_CacheCpuCtrl_WriteByte;
                    185: 
                    186:        /* VME bus - we don't support it yet, but TOS uses FF8E09 to detect the Mega-STE */
                    187:        for (addr = 0xff8e01; addr <= 0xff8e0f; addr += 2)
                    188:        {
                    189:                pInterceptReadTable[addr - 0xff8000] = IoMem_ReadWithoutInterception;
                    190:                pInterceptWriteTable[addr - 0xff8000] = IoMem_WriteWithoutInterception;
                    191:        }
                    192: }
                    193: 
                    194: 
                    195: /**
                    196:  * Fix up table for Falcon in STE compatible bus mode (i.e. less bus errors)
                    197:  */
                    198: static void IoMem_FixVoidAccessForCompatibleFalcon(void)
                    199: {
                    200:        int i;
                    201:        Uint32 no_be_regions[][2] =
                    202:        {
                    203:                { 0xff8002, 0xff8005 },
                    204:                { 0xff8008, 0xff800b },
                    205:                { 0xff800e, 0xff805f },
                    206:                { 0xff8064, 0xff81ff },
                    207:                { 0xff82c4, 0xff83ff },
                    208:                { 0xff8804, 0xff88ff },
                    209:                { 0xff8964, 0xff896f },
                    210:                { 0xff8c00, 0xff8c7f },
                    211:                { 0xff8c88, 0xff8cff },
                    212:                { 0xff9000, 0xff91ff },
                    213:                { 0xff9204, 0xff920f },
                    214:                { 0xff9218, 0xff921f },
                    215:                { 0xff9224, 0xff97ff },
                    216:                { 0xff9c00, 0xff9fff },
                    217:                { 0xffa200, 0xffa207 },
                    218:                { 0, 0 }
                    219:        };
                    220: 
                    221:        for (i = 0; no_be_regions[i][0] != 0; i++)
                    222:        {
                    223:                IoMem_SetVoidRegion(no_be_regions[i][0], no_be_regions[i][1]);
                    224:        }
                    225: }
                    226: 
                    227: 
1.1.1.3   root      228: /**
                    229:  * Create 'intercept' tables for hardware address access. Each 'intercept
                    230:  * table is a list of 0x8000 pointers to a list of functions to call when
                    231:  * that location in the ST's memory is accessed. 
                    232:  */
1.1       root      233: void IoMem_Init(void)
                    234: {
                    235:        Uint32 addr;
                    236:        int i;
1.1.1.2   root      237:        const INTERCEPT_ACCESS_FUNC *pInterceptAccessFuncs = NULL;
1.1       root      238: 
                    239:        /* Set default IO access handler (-> bus error) */
                    240:        IoMem_SetBusErrorRegion(0xff8000, 0xffffff);
                    241: 
                    242:        switch (ConfigureParams.System.nMachineType)
                    243:        {
1.1.1.13  root      244:         case MACHINE_ST:
                    245:                IoMem_FixVoidAccessForST();
                    246:                pInterceptAccessFuncs = IoMemTable_ST;
                    247:                break;
                    248:         case MACHINE_MEGA_ST:
                    249:                IoMem_FixVoidAccessForMegaST();
                    250:                pInterceptAccessFuncs = IoMemTable_ST;
                    251:                break;
                    252:         case MACHINE_STE:
                    253:                pInterceptAccessFuncs = IoMemTable_STE;
                    254:                break;
                    255:         case MACHINE_MEGA_STE:
                    256:                IoMem_FixAccessForMegaSTE();
                    257:                pInterceptAccessFuncs = IoMemTable_STE;
                    258:                break;
                    259:         case MACHINE_TT:
                    260:                pInterceptAccessFuncs = IoMemTable_TT;
                    261:                break;
                    262:         case MACHINE_FALCON:
                    263:                if (falconBusMode == STE_BUS_COMPATIBLE)
                    264:                        IoMem_FixVoidAccessForCompatibleFalcon();
                    265:                pInterceptAccessFuncs = IoMemTable_Falcon;
                    266:                break;
                    267:         default:
                    268:                abort(); /* bug */
1.1       root      269:        }
                    270: 
                    271:        /* Now set the correct handlers */
                    272:        for (addr=0xff8000; addr <= 0xffffff; addr++)
                    273:        {
                    274:                /* Does this hardware location/span appear in our list of possible intercepted functions? */
                    275:                for (i=0; pInterceptAccessFuncs[i].Address != 0; i++)
                    276:                {
                    277:                        if (addr >= pInterceptAccessFuncs[i].Address
                    278:                            && addr < pInterceptAccessFuncs[i].Address+pInterceptAccessFuncs[i].SpanInBytes)
                    279:                        {
                    280:                                /* Security checks... */
                    281:                                if (pInterceptReadTable[addr-0xff8000] != IoMem_BusErrorEvenReadAccess && pInterceptReadTable[addr-0xff8000] != IoMem_BusErrorOddReadAccess)
                    282:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (R) already defined\n", addr);
                    283:                                if (pInterceptWriteTable[addr-0xff8000] != IoMem_BusErrorEvenWriteAccess && pInterceptWriteTable[addr-0xff8000] != IoMem_BusErrorOddWriteAccess)
                    284:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (W) already defined\n", addr);
                    285: 
                    286:                                /* This location needs to be intercepted, so add entry to list */
                    287:                                pInterceptReadTable[addr-0xff8000] = pInterceptAccessFuncs[i].ReadFunc;
                    288:                                pInterceptWriteTable[addr-0xff8000] = pInterceptAccessFuncs[i].WriteFunc;
                    289:                        }
                    290:                }
                    291:        }
                    292: 
1.1.1.4   root      293:        /* Set registers for Falcon DSP emulation */
1.1.1.13  root      294:        if (Config_IsMachineFalcon())
1.1.1.3   root      295:        {
1.1.1.4   root      296:                switch (ConfigureParams.System.nDSPType)
                    297:                {
1.1.1.3   root      298: #if ENABLE_DSP_EMU
                    299:                case DSP_TYPE_EMU:
                    300:                        IoMemTabFalcon_DSPemulation(pInterceptReadTable,
                    301:                                                    pInterceptWriteTable);
                    302:                        break;
                    303: #endif
                    304:                case DSP_TYPE_DUMMY:
                    305:                        IoMemTabFalcon_DSPdummy(pInterceptReadTable,
                    306:                                                pInterceptWriteTable);
                    307:                        break;
                    308:                default:
                    309:                        /* none */
                    310:                        IoMemTabFalcon_DSPnone(pInterceptReadTable,
                    311:                                               pInterceptWriteTable);
                    312:                }
                    313:        }
                    314: 
1.1       root      315:        /* Disable blitter? */
1.1.1.3   root      316:        if (!ConfigureParams.System.bBlitter && ConfigureParams.System.nMachineType == MACHINE_ST)
1.1       root      317:        {
                    318:                IoMem_SetBusErrorRegion(0xff8a00, 0xff8a3f);
                    319:        }
                    320: 
1.1.1.13  root      321:        /* Disable real time clock on non-Mega machines */
                    322:        if (ConfigureParams.System.nMachineType == MACHINE_ST
                    323:            || ConfigureParams.System.nMachineType == MACHINE_STE)
1.1       root      324:        {
1.1.1.4   root      325:                for (addr = 0xfffc21; addr <= 0xfffc3f; addr++)
1.1       root      326:                {
                    327:                        pInterceptReadTable[addr - 0xff8000] = IoMem_VoidRead;     /* For 'read' */
                    328:                        pInterceptWriteTable[addr - 0xff8000] = IoMem_VoidWrite;   /* and 'write' */
                    329:                }
1.1.1.4   root      330:        }
                    331: 
1.1.1.14! root      332:        /* Falcon PSG shadow register range setup (to void access) is already
        !           333:         * done above as part of the IoMem_FixVoidAccessForCompatibleFalcon()
        !           334:         * call (in STE bus compatible mode, otherwise they bus error)
        !           335:         */
1.1.1.13  root      336:        if (!Config_IsMachineFalcon())
1.1.1.4   root      337:        {
1.1.1.14! root      338:                /* Initialize PSG shadow registers for ST, STe, TT machines */
1.1.1.4   root      339:                for (addr = 0xff8804; addr < 0xff8900; addr++)
                    340:                {
                    341:                        pInterceptReadTable[addr - 0xff8000] = pInterceptReadTable[(addr & 0xfff803) - 0xff8000];
                    342:                        pInterceptWriteTable[addr - 0xff8000] = pInterceptWriteTable[(addr & 0xfff803) - 0xff8000];
                    343:                }
1.1.1.8   root      344:        }
1.1       root      345: }
                    346: 
1.1.1.8   root      347: /*-----------------------------------------------------------------------*/
                    348: /**
                    349:  * This function is called to fix falconBusMode (0 = Falcon STe bus compatibility, other value = Falcon only bus compatibility)
                    350:  * This value comes from register $ff8007.b (Bit 5) and is called by ioMemTabFalcon
                    351:  */
                    352: void IoMem_Init_FalconInSTeBuscompatibilityMode(Uint8 value)
                    353: {
                    354:        if (value == 0)
                    355:                falconBusMode = STE_BUS_COMPATIBLE;
                    356:        else
                    357:                falconBusMode = FALCON_ONLY_BUS;
                    358: 
                    359:        IoMem_Init();
                    360: }
1.1       root      361: 
                    362: /*-----------------------------------------------------------------------*/
1.1.1.3   root      363: /**
                    364:  * Uninitialize the IoMem code (currently unused).
                    365:  */
1.1       root      366: void IoMem_UnInit(void)
                    367: {
                    368: }
                    369: 
                    370: 
                    371: /*-----------------------------------------------------------------------*/
1.1.1.3   root      372: /**
                    373:  * Handle byte read access from IO memory.
                    374:  */
1.1.1.13  root      375: uae_u32 REGPARAM3 IoMem_bget(uaecptr addr)
1.1       root      376: {
1.1.1.6   root      377:        Uint8 val;
1.1       root      378: 
1.1.1.14! root      379:        IoAccessFullAddress = addr;                     /* Store initial 32 bits address (eg for bus error stack) */
        !           380: 
1.1.1.13  root      381:        /* Check if access is made by a new instruction or by the same instruction doing multiple byte accesses */
                    382:        if ( IoAccessInstrPrevClock == CyclesGlobalClockCounter )
                    383:                IoAccessInstrCount++;                   /* Same instruction, increase access count */
                    384:        else
                    385:        {
                    386:                IoAccessInstrPrevClock = CyclesGlobalClockCounter;
                    387:                if ( table68k[ M68000_CurrentOpcode ].size == 0 )
                    388:                        IoAccessInstrCount = 0;         /* Instruction size is byte : no multiple accesses */
                    389:                else
                    390:                        IoAccessInstrCount = 1;         /* 1st access */
                    391:        }
                    392: 
1.1       root      393:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    394: 
1.1.1.9   root      395:        if (addr < 0xff8000 || !regs.s)
1.1       root      396:        {
                    397:                /* invalid memory addressing --> bus error */
1.1.1.14! root      398:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      399:                return -1;
                    400:        }
                    401: 
                    402:        IoAccessBaseAddress = addr;                   /* Store access location */
                    403:        nIoMemAccessSize = SIZE_BYTE;
                    404:        nBusErrorAccesses = 0;
                    405: 
                    406:        IoAccessCurrentAddress = addr;
                    407:        pInterceptReadTable[addr-0xff8000]();         /* Call handler */
                    408: 
                    409:        /* Check if we read from a bus-error region */
                    410:        if (nBusErrorAccesses == 1)
                    411:        {
1.1.1.14! root      412:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      413:                return -1;
                    414:        }
                    415: 
1.1.1.6   root      416:        val = IoMem[addr];
                    417: 
1.1.1.14! root      418:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.b $%08x = $%02x pc=%x\n", IoAccessFullAddress, val, M68000_GetPC());
1.1.1.6   root      419: 
                    420:        return val;
1.1       root      421: }
                    422: 
                    423: 
                    424: /*-----------------------------------------------------------------------*/
1.1.1.3   root      425: /**
                    426:  * Handle word read access from IO memory.
                    427:  */
1.1.1.13  root      428: uae_u32 REGPARAM3 IoMem_wget(uaecptr addr)
1.1       root      429: {
                    430:        Uint32 idx;
1.1.1.6   root      431:        Uint16 val;
1.1       root      432: 
1.1.1.14! root      433:        IoAccessFullAddress = addr;                     /* Store initial 32 bits address (eg for bus error stack) */
        !           434: 
1.1.1.13  root      435:        /* Check if access is made by a new instruction or by the same instruction doing multiple word accesses */
                    436:        if ( IoAccessInstrPrevClock == CyclesGlobalClockCounter )
                    437:                IoAccessInstrCount++;                   /* Same instruction, increase access count */
                    438:        else
                    439:        {
                    440:                IoAccessInstrPrevClock = CyclesGlobalClockCounter;
                    441:                if ( ( table68k[ M68000_CurrentOpcode ].size == 1 )
                    442:                  && ( OpcodeFamily != i_MVMEL ) && ( OpcodeFamily != i_MVMLE ) )
                    443:                        IoAccessInstrCount = 0;         /* Instruction size is word and not a movem : no multiple accesses */
                    444:                else
                    445:                        IoAccessInstrCount = 1;         /* 1st access of a long or movem.w */
                    446:        }
                    447: 
1.1       root      448:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    449: 
1.1.1.9   root      450:        if (addr < 0xff8000 || !regs.s)
1.1       root      451:        {
                    452:                /* invalid memory addressing --> bus error */
1.1.1.14! root      453:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      454:                return -1;
                    455:        }
                    456:        if (addr > 0xfffffe)
                    457:        {
                    458:                fprintf(stderr, "Illegal IO memory access: IoMem_wget($%x)\n", addr);
                    459:                return -1;
                    460:        }
                    461: 
                    462:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    463:        nIoMemAccessSize = SIZE_WORD;
                    464:        nBusErrorAccesses = 0;
                    465:        idx = addr - 0xff8000;
                    466: 
                    467:        IoAccessCurrentAddress = addr;
                    468:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    469: 
                    470:        if (pInterceptReadTable[idx+1] != pInterceptReadTable[idx])
                    471:        {
                    472:                IoAccessCurrentAddress = addr + 1;
                    473:                pInterceptReadTable[idx+1]();             /* Call 2nd handler */
                    474:        }
                    475: 
                    476:        /* Check if we completely read from a bus-error region */
                    477:        if (nBusErrorAccesses == 2)
                    478:        {
1.1.1.14! root      479:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      480:                return -1;
                    481:        }
                    482: 
1.1.1.6   root      483:        val = IoMem_ReadWord(addr);
                    484: 
1.1.1.14! root      485:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.w $%08x = $%04x pc=%x\n", IoAccessFullAddress, val, M68000_GetPC());
1.1.1.6   root      486: 
                    487:        return val;
1.1       root      488: }
                    489: 
                    490: 
                    491: /*-----------------------------------------------------------------------*/
1.1.1.3   root      492: /**
                    493:  * Handle long-word read access from IO memory.
                    494:  */
1.1.1.13  root      495: uae_u32 REGPARAM3 IoMem_lget(uaecptr addr)
1.1       root      496: {
                    497:        Uint32 idx;
1.1.1.6   root      498:        Uint32 val;
1.1.1.12  root      499:        int n;
1.1       root      500: 
1.1.1.14! root      501:        IoAccessFullAddress = addr;                     /* Store initial 32 bits address (eg for bus error stack) */
        !           502: 
1.1.1.13  root      503:        /* Check if access is made by a new instruction or by the same instruction doing multiple long accesses */
                    504:        if ( IoAccessInstrPrevClock == CyclesGlobalClockCounter )
                    505:                IoAccessInstrCount++;                   /* Same instruction, increase access count */
                    506:        else
                    507:        {
                    508:                IoAccessInstrPrevClock = CyclesGlobalClockCounter;
                    509:                if ( ( OpcodeFamily != i_MVMEL ) && ( OpcodeFamily != i_MVMLE ) )
                    510:                        IoAccessInstrCount = 0;         /* Instruction is not a movem : no multiple accesses */
                    511:                else
                    512:                        IoAccessInstrCount = 1;         /* 1st access of a movem.l */
                    513:        }
                    514: 
1.1       root      515:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    516: 
1.1.1.9   root      517:        if (addr < 0xff8000 || !regs.s)
1.1       root      518:        {
                    519:                /* invalid memory addressing --> bus error */
1.1.1.14! root      520:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      521:                return -1;
                    522:        }
                    523:        if (addr > 0xfffffc)
                    524:        {
                    525:                fprintf(stderr, "Illegal IO memory access: IoMem_lget($%x)\n", addr);
                    526:                return -1;
                    527:        }
                    528: 
                    529:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    530:        nIoMemAccessSize = SIZE_LONG;
                    531:        nBusErrorAccesses = 0;
                    532:        idx = addr - 0xff8000;
                    533: 
                    534:        IoAccessCurrentAddress = addr;
                    535:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    536: 
1.1.1.12  root      537:        for (n = 1; n < nIoMemAccessSize; n++)
1.1       root      538:        {
1.1.1.12  root      539:                if (pInterceptReadTable[idx+n] != pInterceptReadTable[idx+n-1])
                    540:                {
                    541:                        IoAccessCurrentAddress = addr + n;
                    542:                        pInterceptReadTable[idx+n]();     /* Call n-th handler */
                    543:                }
1.1       root      544:        }
                    545: 
                    546:        /* Check if we completely read from a bus-error region */
                    547:        if (nBusErrorAccesses == 4)
                    548:        {
1.1.1.14! root      549:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_READ, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      550:                return -1;
                    551:        }
                    552: 
1.1.1.6   root      553:        val = IoMem_ReadLong(addr);
                    554: 
1.1.1.14! root      555:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.l $%08x = $%08x pc=%x\n", IoAccessFullAddress, val, M68000_GetPC());
1.1.1.6   root      556: 
                    557:        return val;
1.1       root      558: }
                    559: 
                    560: 
                    561: /*-----------------------------------------------------------------------*/
1.1.1.3   root      562: /**
                    563:  * Handle byte write access to IO memory.
                    564:  */
1.1.1.13  root      565: void REGPARAM3 IoMem_bput(uaecptr addr, uae_u32 val)
1.1       root      566: {
1.1.1.14! root      567:        IoAccessFullAddress = addr;                     /* Store initial 32 bits address (eg for bus error stack) */
        !           568: 
1.1.1.13  root      569:        /* Check if access is made by a new instruction or by the same instruction doing multiple byte accesses */
                    570:        if ( IoAccessInstrPrevClock == CyclesGlobalClockCounter )
                    571:                IoAccessInstrCount++;                   /* Same instruction, increase access count */
                    572:        else
                    573:        {
                    574:                IoAccessInstrPrevClock = CyclesGlobalClockCounter;
                    575:                if ( table68k[ M68000_CurrentOpcode ].size == 0 )
                    576:                        IoAccessInstrCount = 0;         /* Instruction size is byte : no multiple accesses */
                    577:                else
                    578:                        IoAccessInstrCount = 1;         /* 1st access */
                    579:        }
                    580: 
1.1       root      581:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    582: 
1.1.1.14! root      583:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.b $%08x = $%02x pc=%x\n", IoAccessFullAddress, val&0xff, M68000_GetPC());
1.1.1.6   root      584: 
1.1.1.5   root      585:        if (addr < 0xff8000 || !regs.s)
1.1       root      586:        {
                    587:                /* invalid memory addressing --> bus error */
1.1.1.14! root      588:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      589:                return;
                    590:        }
                    591: 
                    592:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    593:        nIoMemAccessSize = SIZE_BYTE;
                    594:        nBusErrorAccesses = 0;
                    595: 
                    596:        IoMem[addr] = val;
                    597: 
                    598:        IoAccessCurrentAddress = addr;
                    599:        pInterceptWriteTable[addr-0xff8000]();        /* Call handler */
                    600: 
                    601:        /* Check if we wrote to a bus-error region */
                    602:        if (nBusErrorAccesses == 1)
                    603:        {
1.1.1.14! root      604:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      605:        }
                    606: }
                    607: 
                    608: 
                    609: /*-----------------------------------------------------------------------*/
1.1.1.3   root      610: /**
                    611:  * Handle word write access to IO memory.
                    612:  */
1.1.1.13  root      613: void REGPARAM3 IoMem_wput(uaecptr addr, uae_u32 val)
1.1       root      614: {
                    615:        Uint32 idx;
                    616: 
1.1.1.14! root      617:        IoAccessFullAddress = addr;                     /* Store initial 32 bits address (eg for bus error stack) */
        !           618: 
1.1.1.13  root      619:        /* Check if access is made by a new instruction or by the same instruction doing multiple word accesses */
                    620:        if ( IoAccessInstrPrevClock == CyclesGlobalClockCounter )
                    621:                IoAccessInstrCount++;                   /* Same instruction, increase access count */
                    622:        else
                    623:        {
                    624:                IoAccessInstrPrevClock = CyclesGlobalClockCounter;
                    625:                if ( ( table68k[ M68000_CurrentOpcode ].size == 1 )
                    626:                  && ( OpcodeFamily != i_MVMEL ) && ( OpcodeFamily != i_MVMLE ) )
                    627:                        IoAccessInstrCount = 0;         /* Instruction size is word and not a movem : no multiple accesses */
                    628:                else
                    629:                        IoAccessInstrCount = 1;         /* 1st access of a long or movem.w */
                    630:        }
                    631: 
1.1       root      632:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    633: 
1.1.1.14! root      634:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.w $%08x = $%04x pc=%x\n", IoAccessFullAddress, val&0xffff, M68000_GetPC());
1.1.1.6   root      635: 
1.1.1.5   root      636:        if (addr < 0x00ff8000 || !regs.s)
1.1       root      637:        {
                    638:                /* invalid memory addressing --> bus error */
1.1.1.14! root      639:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      640:                return;
                    641:        }
                    642:        if (addr > 0xfffffe)
                    643:        {
                    644:                fprintf(stderr, "Illegal IO memory access: IoMem_wput($%x)\n", addr);
                    645:                return;
                    646:        }
                    647: 
                    648:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    649:        nIoMemAccessSize = SIZE_WORD;
                    650:        nBusErrorAccesses = 0;
                    651: 
                    652:        IoMem_WriteWord(addr, val);
                    653:        idx = addr - 0xff8000;
                    654: 
                    655:        IoAccessCurrentAddress = addr;
                    656:        pInterceptWriteTable[idx]();                  /* Call 1st handler */
                    657: 
                    658:        if (pInterceptWriteTable[idx+1] != pInterceptWriteTable[idx])
                    659:        {
                    660:                IoAccessCurrentAddress = addr + 1;
                    661:                pInterceptWriteTable[idx+1]();            /* Call 2nd handler */
                    662:        }
                    663: 
                    664:        /* Check if we wrote to a bus-error region */
                    665:        if (nBusErrorAccesses == 2)
                    666:        {
1.1.1.14! root      667:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      668:        }
                    669: }
                    670: 
                    671: 
                    672: /*-----------------------------------------------------------------------*/
1.1.1.3   root      673: /**
                    674:  * Handle long-word write access to IO memory.
                    675:  */
1.1.1.13  root      676: void REGPARAM3 IoMem_lput(uaecptr addr, uae_u32 val)
1.1       root      677: {
                    678:        Uint32 idx;
1.1.1.12  root      679:        int n;
1.1       root      680: 
1.1.1.14! root      681:        IoAccessFullAddress = addr;                     /* Store initial 32 bits address (eg for bus error stack) */
        !           682: 
1.1.1.13  root      683:        /* Check if access is made by a new instruction or by the same instruction doing multiple long accesses */
                    684:        if ( IoAccessInstrPrevClock == CyclesGlobalClockCounter )
                    685:                IoAccessInstrCount++;                   /* Same instruction, increase access count */
                    686:        else
                    687:        {
                    688:                IoAccessInstrPrevClock = CyclesGlobalClockCounter;
                    689:                if ( ( OpcodeFamily != i_MVMEL ) && ( OpcodeFamily != i_MVMLE ) )
                    690:                        IoAccessInstrCount = 0;         /* Instruction is not a movem : no multiple accesses */
                    691:                else
                    692:                        IoAccessInstrCount = 1;         /* 1st access of a movem.l */
                    693:        }
                    694: 
1.1       root      695:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    696: 
1.1.1.14! root      697:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.l $%08x = $%08x pc=%x\n", IoAccessFullAddress, val, M68000_GetPC());
1.1.1.6   root      698: 
1.1.1.5   root      699:        if (addr < 0xff8000 || !regs.s)
1.1       root      700:        {
                    701:                /* invalid memory addressing --> bus error */
1.1.1.14! root      702:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      703:                return;
                    704:        }
                    705:        if (addr > 0xfffffc)
                    706:        {
                    707:                fprintf(stderr, "Illegal IO memory access: IoMem_lput($%x)\n", addr);
                    708:                return;
                    709:        }
                    710: 
                    711:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    712:        nIoMemAccessSize = SIZE_LONG;
                    713:        nBusErrorAccesses = 0;
                    714: 
                    715:        IoMem_WriteLong(addr, val);
                    716:        idx = addr - 0xff8000;
                    717: 
                    718:        IoAccessCurrentAddress = addr;
1.1.1.12  root      719:        pInterceptWriteTable[idx]();                  /* Call first handler */
1.1       root      720: 
1.1.1.12  root      721:        for (n = 1; n < nIoMemAccessSize; n++)
1.1       root      722:        {
1.1.1.12  root      723:                if (pInterceptWriteTable[idx+n] != pInterceptWriteTable[idx+n-1])
                    724:                {
                    725:                        IoAccessCurrentAddress = addr + n;
                    726:                        pInterceptWriteTable[idx+n]();   /* Call n-th handler */
                    727:                }
1.1       root      728:        }
                    729: 
                    730:        /* Check if we wrote to a bus-error region */
                    731:        if (nBusErrorAccesses == 4)
                    732:        {
1.1.1.14! root      733:                M68000_BusError(IoAccessFullAddress, BUS_ERROR_WRITE, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      734:        }
                    735: }
                    736: 
                    737: 
                    738: /*-------------------------------------------------------------------------*/
1.1.1.3   root      739: /**
                    740:  * This handler will be called if a ST program tries to read from an address
                    741:  * that causes a bus error on a real ST. However, we can't call M68000_BusError()
                    742:  * directly: For example, a "move.b $ff8204,d0" triggers a bus error on a real ST,
                    743:  * while a "move.w $ff8204,d0" works! So we have to count the accesses to bus error
                    744:  * addresses and we only trigger a bus error later if the count matches the complete
                    745:  * access size (e.g. nBusErrorAccesses==4 for a long word access).
                    746:  */
1.1       root      747: void IoMem_BusErrorEvenReadAccess(void)
                    748: {
                    749:        nBusErrorAccesses += 1;
                    750:        IoMem[IoAccessCurrentAddress] = 0xff;
                    751: }
                    752: 
1.1.1.3   root      753: /**
                    754:  * We need two handler so that the IoMem_*get functions can distinguish
                    755:  * consecutive addresses.
                    756:  */
1.1       root      757: void IoMem_BusErrorOddReadAccess(void)
                    758: {
                    759:        nBusErrorAccesses += 1;
                    760:        IoMem[IoAccessCurrentAddress] = 0xff;
                    761: }
                    762: 
                    763: /*-------------------------------------------------------------------------*/
1.1.1.3   root      764: /**
                    765:  * Same as IoMem_BusErrorReadAccess() but for write access this time.
                    766:  */
1.1       root      767: void IoMem_BusErrorEvenWriteAccess(void)
                    768: {
                    769:        nBusErrorAccesses += 1;
                    770: }
                    771: 
1.1.1.3   root      772: /**
                    773:  * We need two handler so that the IoMem_*put functions can distinguish
                    774:  * consecutive addresses.
                    775:  */
1.1       root      776: void IoMem_BusErrorOddWriteAccess(void)
                    777: {
                    778:        nBusErrorAccesses += 1;
                    779: }
                    780: 
                    781: 
                    782: /*-------------------------------------------------------------------------*/
1.1.1.3   root      783: /**
                    784:  * This is the read handler for the IO memory locations without an assigned
                    785:  * IO register and which also do not generate a bus error. Reading from such
                    786:  * a register will return the result 0xff.
                    787:  */
1.1       root      788: void IoMem_VoidRead(void)
                    789: {
                    790:        Uint32 a;
                    791: 
                    792:        /* handler is probably called only once, so we have to take care of the neighbour "void IO registers" */
                    793:        for (a = IoAccessBaseAddress; a < IoAccessBaseAddress + nIoMemAccessSize; a++)
                    794:        {
                    795:                if (pInterceptReadTable[a - 0xff8000] == IoMem_VoidRead)
                    796:                {
                    797:                        IoMem[a] = 0xff;
                    798:                }
                    799:        }
                    800: }
                    801: 
                    802: /*-------------------------------------------------------------------------*/
1.1.1.3   root      803: /**
1.1.1.8   root      804:  * This is the same function as IoMem_VoidRead, but for IO registers that
                    805:  * return 0x00 instead of 0xff when read (this is the case for some video
                    806:  * registers on STE, Falcon, ...)
                    807:  */
                    808: void IoMem_VoidRead_00(void)
                    809: {
                    810:        Uint32 a;
                    811: 
                    812:        /* handler is probably called only once, so we have to take care of the neighbour "void IO registers" */
                    813:        for (a = IoAccessBaseAddress; a < IoAccessBaseAddress + nIoMemAccessSize; a++)
                    814:        {
                    815:                if (pInterceptReadTable[a - 0xff8000] == IoMem_VoidRead_00)
                    816:                {
                    817:                        IoMem[a] = 0x00;
                    818:                }
                    819:        }
                    820: }
                    821: 
                    822: /*-------------------------------------------------------------------------*/
                    823: /**
1.1.1.3   root      824:  * This is the write handler for the IO memory locations without an assigned
                    825:  * IO register and which also do not generate a bus error. We simply ignore
                    826:  * a write access to these registers.
                    827:  */
1.1       root      828: void IoMem_VoidWrite(void)
                    829: {
                    830:        /* Nothing... */
                    831: }
                    832: 
                    833: 
                    834: /*-------------------------------------------------------------------------*/
1.1.1.3   root      835: /**
                    836:  * A dummy function that does nothing at all - for memory regions that don't
                    837:  * need a special handler for read access.
                    838:  */
1.1       root      839: void IoMem_ReadWithoutInterception(void)
                    840: {
                    841:        /* Nothing... */
                    842: }
                    843: 
                    844: /*-------------------------------------------------------------------------*/
1.1.1.3   root      845: /**
                    846:  * A dummy function that does nothing at all - for memory regions that don't
                    847:  * need a special handler for write access.
                    848:  */
1.1       root      849: void IoMem_WriteWithoutInterception(void)
                    850: {
                    851:        /* Nothing... */
                    852: }

unix.superglobalmegacorp.com

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