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

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

unix.superglobalmegacorp.com

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