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

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       root       40: 
                     41: 
                     42: static void (*pInterceptReadTable[0x8000])(void);     /* Table with read access handlers */
                     43: static void (*pInterceptWriteTable[0x8000])(void);    /* Table with write access handlers */
                     44: 
                     45: int nIoMemAccessSize;                                 /* Set to 1, 2 or 4 according to byte, word or long word access */
                     46: Uint32 IoAccessBaseAddress;                           /* Stores the base address of the IO mem access */
1.1.1.3   root       47: Uint32 IoAccessCurrentAddress;                        /* Current byte address while handling WORD and LONG accesses */
1.1       root       48: static int nBusErrorAccesses;                         /* Needed to count bus error accesses */
                     49: 
1.1.1.8   root       50: /* Falcon bus mode (Falcon STe compatible bus or Falcon only bus) */
                     51: static enum {
                     52:        STE_BUS_COMPATIBLE,
                     53:        FALCON_ONLY_BUS
                     54: } falconBusMode;
                     55: 
                     56: /*-----------------------------------------------------------------------*/
                     57: /**
                     58:  * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type)
                     59:  */
                     60: void IoMem_MemorySnapShot_Capture(bool bSave)
                     61: {
                     62:        /* Save/Restore details */
                     63:        MemorySnapShot_Store(&falconBusMode, sizeof(falconBusMode));
                     64: }
1.1       root       65: 
                     66: /*-----------------------------------------------------------------------*/
1.1.1.3   root       67: /**
                     68:  * Fill a region with bus error handlers.
                     69:  */
1.1       root       70: static void IoMem_SetBusErrorRegion(Uint32 startaddr, Uint32 endaddr)
                     71: {
                     72:        Uint32 a;
                     73: 
                     74:        for (a = startaddr; a <= endaddr; a++)
                     75:        {
                     76:                if (a & 1)
                     77:                {
                     78:                        pInterceptReadTable[a - 0xff8000] = IoMem_BusErrorOddReadAccess;     /* For 'read' */
                     79:                        pInterceptWriteTable[a - 0xff8000] = IoMem_BusErrorOddWriteAccess;   /* and 'write' */
                     80:                }
                     81:                else
                     82:                {
                     83:                        pInterceptReadTable[a - 0xff8000] = IoMem_BusErrorEvenReadAccess;    /* For 'read' */
                     84:                        pInterceptWriteTable[a - 0xff8000] = IoMem_BusErrorEvenWriteAccess;  /* and 'write' */
                     85:                }
                     86:        }
                     87: }
                     88: 
                     89: 
                     90: /*-----------------------------------------------------------------------*/
1.1.1.3   root       91: /**
                     92:  * Create 'intercept' tables for hardware address access. Each 'intercept
                     93:  * table is a list of 0x8000 pointers to a list of functions to call when
                     94:  * that location in the ST's memory is accessed. 
                     95:  */
1.1       root       96: void IoMem_Init(void)
                     97: {
                     98:        Uint32 addr;
                     99:        int i;
1.1.1.2   root      100:        const INTERCEPT_ACCESS_FUNC *pInterceptAccessFuncs = NULL;
1.1       root      101: 
                    102:        /* Set default IO access handler (-> bus error) */
                    103:        IoMem_SetBusErrorRegion(0xff8000, 0xffffff);
                    104: 
1.1.1.8   root      105: 
                    106:        /* Initialize STe bus specific registers for Falcon in FALCON STe compatible bus mode */
                    107:        if ((ConfigureParams.System.nMachineType == MACHINE_FALCON) && (falconBusMode == STE_BUS_COMPATIBLE)) {
                    108:                for (addr = 0xff8000; addr < 0xffd426; addr++)
                    109:                {
                    110:                        if ( ((addr >= 0xff8002) && (addr < 0xff8006)) ||
                    111:                                 ((addr >= 0xff8008) && (addr < 0xff800c)) ||
                    112:                                 ((addr >= 0xff800e) && (addr < 0xff8060)) ||
                    113:                                 ((addr >= 0xff8064) && (addr < 0xff8200)) ||
                    114:                                 ((addr >= 0xff82c4) && (addr < 0xff8400)) ||
                    115:                                  (addr == 0xff8560)                       ||
                    116:                                  (addr == 0xff8564)                       ||
                    117:                                 ((addr >= 0xff8804) && (addr < 0xff8900)) ||
                    118:                                 ((addr >= 0xff8964) && (addr < 0xff8970)) ||
                    119:                                 ((addr >= 0xff8c00) && (addr < 0xff8c80)) ||
                    120:                                 ((addr >= 0xff8c88) && (addr < 0xff8d00)) ||
                    121:                                 ((addr >= 0xff9000) && (addr < 0xff9200)) ||
                    122:                                 ((addr >= 0xff9204) && (addr < 0xff9206)) ||
                    123:                                 ((addr >= 0xff9207) && (addr < 0xff9210)) ||
                    124:                                 ((addr >= 0xff9218) && (addr < 0xff9220)) ||
                    125:                                 ((addr >= 0xff9224) && (addr < 0xff9800)) ||
                    126:                                 ((addr >= 0xff9c00) && (addr < 0xffa000)) ||
                    127:                                 ((addr >= 0xffa200) && (addr < 0xffa208)) ||
                    128:                                  (addr == 0xffc020)                       ||
                    129:                                  (addr == 0xffc021)                       ||
                    130:                                  (addr == 0xffd020)                       ||
                    131:                                  (addr == 0xffd021)                       ||
                    132:                                  (addr == 0xffd420)                       ||
                    133:                                  (addr == 0xffd421)                       ||
                    134:                                  (addr == 0xffd425)
                    135:                          ) {
                    136:                                        pInterceptReadTable[addr - 0xff8000] = IoMem_VoidRead;      /* For 'read' */
                    137:                                        pInterceptWriteTable[addr - 0xff8000] = IoMem_VoidWrite;    /* and 'write' */
                    138:                            }
                    139:                }
                    140:        }
                    141: 
1.1       root      142:        switch (ConfigureParams.System.nMachineType)
                    143:        {
                    144:                case MACHINE_ST:  pInterceptAccessFuncs = IoMemTable_ST; break;
                    145:                case MACHINE_STE: pInterceptAccessFuncs = IoMemTable_STE; break;
1.1.1.2   root      146:                case MACHINE_TT: pInterceptAccessFuncs = IoMemTable_TT; break;
1.1.1.3   root      147:                case MACHINE_FALCON: pInterceptAccessFuncs = IoMemTable_Falcon; break;
1.1.1.8   root      148:                default: abort(); /* bug */
1.1       root      149:        }
                    150: 
                    151:        /* Now set the correct handlers */
                    152:        for (addr=0xff8000; addr <= 0xffffff; addr++)
                    153:        {
                    154:                /* Does this hardware location/span appear in our list of possible intercepted functions? */
                    155:                for (i=0; pInterceptAccessFuncs[i].Address != 0; i++)
                    156:                {
                    157:                        if (addr >= pInterceptAccessFuncs[i].Address
                    158:                            && addr < pInterceptAccessFuncs[i].Address+pInterceptAccessFuncs[i].SpanInBytes)
                    159:                        {
                    160:                                /* Security checks... */
                    161:                                if (pInterceptReadTable[addr-0xff8000] != IoMem_BusErrorEvenReadAccess && pInterceptReadTable[addr-0xff8000] != IoMem_BusErrorOddReadAccess)
                    162:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (R) already defined\n", addr);
                    163:                                if (pInterceptWriteTable[addr-0xff8000] != IoMem_BusErrorEvenWriteAccess && pInterceptWriteTable[addr-0xff8000] != IoMem_BusErrorOddWriteAccess)
                    164:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (W) already defined\n", addr);
                    165: 
                    166:                                /* This location needs to be intercepted, so add entry to list */
                    167:                                pInterceptReadTable[addr-0xff8000] = pInterceptAccessFuncs[i].ReadFunc;
                    168:                                pInterceptWriteTable[addr-0xff8000] = pInterceptAccessFuncs[i].WriteFunc;
                    169:                        }
                    170:                }
                    171:        }
                    172: 
1.1.1.4   root      173:        /* Set registers for Falcon DSP emulation */
1.1.1.3   root      174:        if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
                    175:        {
1.1.1.4   root      176:                switch (ConfigureParams.System.nDSPType)
                    177:                {
1.1.1.3   root      178: #if ENABLE_DSP_EMU
                    179:                case DSP_TYPE_EMU:
                    180:                        IoMemTabFalcon_DSPemulation(pInterceptReadTable,
                    181:                                                    pInterceptWriteTable);
                    182:                        break;
                    183: #endif
                    184:                case DSP_TYPE_DUMMY:
                    185:                        IoMemTabFalcon_DSPdummy(pInterceptReadTable,
                    186:                                                pInterceptWriteTable);
                    187:                        break;
                    188:                default:
                    189:                        /* none */
                    190:                        IoMemTabFalcon_DSPnone(pInterceptReadTable,
                    191:                                               pInterceptWriteTable);
                    192:                }
                    193:        }
                    194: 
1.1       root      195:        /* Disable blitter? */
1.1.1.3   root      196:        if (!ConfigureParams.System.bBlitter && ConfigureParams.System.nMachineType == MACHINE_ST)
1.1       root      197:        {
                    198:                IoMem_SetBusErrorRegion(0xff8a00, 0xff8a3f);
                    199:        }
                    200: 
                    201:        /* Disable real time clock? */
                    202:        if (!ConfigureParams.System.bRealTimeClock)
                    203:        {
1.1.1.4   root      204:                for (addr = 0xfffc21; addr <= 0xfffc3f; addr++)
1.1       root      205:                {
                    206:                        pInterceptReadTable[addr - 0xff8000] = IoMem_VoidRead;     /* For 'read' */
                    207:                        pInterceptWriteTable[addr - 0xff8000] = IoMem_VoidWrite;   /* and 'write' */
                    208:                }
1.1.1.4   root      209:        }
                    210: 
1.1.1.8   root      211:        /* Initialize PSG shadow registers for ST, STe, TT machines */
1.1.1.4   root      212:        if (ConfigureParams.System.nMachineType != MACHINE_FALCON)
                    213:        {
                    214:                for (addr = 0xff8804; addr < 0xff8900; addr++)
                    215:                {
                    216:                        pInterceptReadTable[addr - 0xff8000] = pInterceptReadTable[(addr & 0xfff803) - 0xff8000];
                    217:                        pInterceptWriteTable[addr - 0xff8000] = pInterceptWriteTable[(addr & 0xfff803) - 0xff8000];
                    218:                }
1.1.1.8   root      219:        }
                    220:        else {
                    221:                /* Initialize PSG shadow registers for Falcon machine when in STe bus compatibility mode */
                    222:                if (falconBusMode == STE_BUS_COMPATIBLE) {
                    223:                        for (addr = 0xff8804; addr < 0xff8900; addr++)
                    224:                        {
                    225:                                pInterceptReadTable[addr - 0xff8000] = IoMem_VoidRead;     /* For 'read' */
                    226:                                pInterceptWriteTable[addr - 0xff8000] = IoMem_VoidWrite;   /* and 'write' */
                    227:                        }
                    228: 
                    229:                }
1.1       root      230:        }
                    231: }
                    232: 
1.1.1.8   root      233: /*-----------------------------------------------------------------------*/
                    234: /**
                    235:  * This function is called to fix falconBusMode (0 = Falcon STe bus compatibility, other value = Falcon only bus compatibility)
                    236:  * This value comes from register $ff8007.b (Bit 5) and is called by ioMemTabFalcon
                    237:  */
                    238: void IoMem_Init_FalconInSTeBuscompatibilityMode(Uint8 value)
                    239: {
                    240:        if (value == 0)
                    241:                falconBusMode = STE_BUS_COMPATIBLE;
                    242:        else
                    243:                falconBusMode = FALCON_ONLY_BUS;
                    244: 
                    245:        IoMem_Init();
                    246: }
1.1       root      247: 
                    248: /*-----------------------------------------------------------------------*/
1.1.1.3   root      249: /**
                    250:  * Uninitialize the IoMem code (currently unused).
                    251:  */
1.1       root      252: void IoMem_UnInit(void)
                    253: {
                    254: }
                    255: 
                    256: 
                    257: /*-----------------------------------------------------------------------*/
1.1.1.3   root      258: /**
                    259:  * Handle byte read access from IO memory.
                    260:  */
1.1       root      261: uae_u32 IoMem_bget(uaecptr addr)
                    262: {
1.1.1.6   root      263:        Uint8 val;
1.1       root      264: 
                    265:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    266: 
1.1.1.9   root      267:        if (addr < 0xff8000 || !regs.s)
1.1       root      268:        {
                    269:                /* invalid memory addressing --> bus error */
1.1.1.12! root      270:                M68000_BusError(addr, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      271:                return -1;
                    272:        }
                    273: 
                    274:        IoAccessBaseAddress = addr;                   /* Store access location */
                    275:        nIoMemAccessSize = SIZE_BYTE;
                    276:        nBusErrorAccesses = 0;
                    277: 
                    278:        IoAccessCurrentAddress = addr;
                    279:        pInterceptReadTable[addr-0xff8000]();         /* Call handler */
                    280: 
                    281:        /* Check if we read from a bus-error region */
                    282:        if (nBusErrorAccesses == 1)
                    283:        {
1.1.1.12! root      284:                M68000_BusError(addr, BUS_ERROR_READ, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      285:                return -1;
                    286:        }
                    287: 
1.1.1.6   root      288:        val = IoMem[addr];
                    289: 
1.1.1.11  root      290:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.b $%06x = $%02x pc=%x\n", addr, val, M68000_GetPC());
1.1.1.6   root      291: 
                    292:        return val;
1.1       root      293: }
                    294: 
                    295: 
                    296: /*-----------------------------------------------------------------------*/
1.1.1.3   root      297: /**
                    298:  * Handle word read access from IO memory.
                    299:  */
1.1       root      300: uae_u32 IoMem_wget(uaecptr addr)
                    301: {
                    302:        Uint32 idx;
1.1.1.6   root      303:        Uint16 val;
1.1       root      304: 
                    305:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    306: 
1.1.1.9   root      307:        if (addr < 0xff8000 || !regs.s)
1.1       root      308:        {
                    309:                /* invalid memory addressing --> bus error */
1.1.1.12! root      310:                M68000_BusError(addr, BUS_ERROR_READ, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      311:                return -1;
                    312:        }
                    313:        if (addr > 0xfffffe)
                    314:        {
                    315:                fprintf(stderr, "Illegal IO memory access: IoMem_wget($%x)\n", addr);
                    316:                return -1;
                    317:        }
                    318: 
                    319:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    320:        nIoMemAccessSize = SIZE_WORD;
                    321:        nBusErrorAccesses = 0;
                    322:        idx = addr - 0xff8000;
                    323: 
                    324:        IoAccessCurrentAddress = addr;
                    325:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    326: 
                    327:        if (pInterceptReadTable[idx+1] != pInterceptReadTable[idx])
                    328:        {
                    329:                IoAccessCurrentAddress = addr + 1;
                    330:                pInterceptReadTable[idx+1]();             /* Call 2nd handler */
                    331:        }
                    332: 
                    333:        /* Check if we completely read from a bus-error region */
                    334:        if (nBusErrorAccesses == 2)
                    335:        {
1.1.1.12! root      336:                M68000_BusError(addr, BUS_ERROR_READ, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      337:                return -1;
                    338:        }
                    339: 
1.1.1.6   root      340:        val = IoMem_ReadWord(addr);
                    341: 
1.1.1.11  root      342:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.w $%06x = $%04x pc=%x\n", addr, val, M68000_GetPC());
1.1.1.6   root      343: 
                    344:        return val;
1.1       root      345: }
                    346: 
                    347: 
                    348: /*-----------------------------------------------------------------------*/
1.1.1.3   root      349: /**
                    350:  * Handle long-word read access from IO memory.
                    351:  */
1.1       root      352: uae_u32 IoMem_lget(uaecptr addr)
                    353: {
                    354:        Uint32 idx;
1.1.1.6   root      355:        Uint32 val;
1.1.1.12! root      356:        int n;
1.1       root      357: 
                    358:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    359: 
1.1.1.9   root      360:        if (addr < 0xff8000 || !regs.s)
1.1       root      361:        {
                    362:                /* invalid memory addressing --> bus error */
1.1.1.12! root      363:                M68000_BusError(addr, BUS_ERROR_READ, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      364:                return -1;
                    365:        }
                    366:        if (addr > 0xfffffc)
                    367:        {
                    368:                fprintf(stderr, "Illegal IO memory access: IoMem_lget($%x)\n", addr);
                    369:                return -1;
                    370:        }
                    371: 
                    372:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    373:        nIoMemAccessSize = SIZE_LONG;
                    374:        nBusErrorAccesses = 0;
                    375:        idx = addr - 0xff8000;
                    376: 
                    377:        IoAccessCurrentAddress = addr;
                    378:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    379: 
1.1.1.12! root      380:        for (n = 1; n < nIoMemAccessSize; n++)
1.1       root      381:        {
1.1.1.12! root      382:                if (pInterceptReadTable[idx+n] != pInterceptReadTable[idx+n-1])
        !           383:                {
        !           384:                        IoAccessCurrentAddress = addr + n;
        !           385:                        pInterceptReadTable[idx+n]();     /* Call n-th handler */
        !           386:                }
1.1       root      387:        }
                    388: 
                    389:        /* Check if we completely read from a bus-error region */
                    390:        if (nBusErrorAccesses == 4)
                    391:        {
1.1.1.12! root      392:                M68000_BusError(addr, BUS_ERROR_READ, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      393:                return -1;
                    394:        }
                    395: 
1.1.1.6   root      396:        val = IoMem_ReadLong(addr);
                    397: 
1.1.1.11  root      398:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.l $%06x = $%08x pc=%x\n", addr, val, M68000_GetPC());
1.1.1.6   root      399: 
                    400:        return val;
1.1       root      401: }
                    402: 
                    403: 
                    404: /*-----------------------------------------------------------------------*/
1.1.1.3   root      405: /**
                    406:  * Handle byte write access to IO memory.
                    407:  */
1.1       root      408: void IoMem_bput(uaecptr addr, uae_u32 val)
                    409: {
                    410:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    411: 
1.1.1.11  root      412:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.b $%06x = $%02x pc=%x\n", addr, val&0x0ff, M68000_GetPC());
1.1.1.6   root      413: 
1.1.1.5   root      414:        if (addr < 0xff8000 || !regs.s)
1.1       root      415:        {
                    416:                /* invalid memory addressing --> bus error */
1.1.1.12! root      417:                M68000_BusError(addr, BUS_ERROR_WRITE, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      418:                return;
                    419:        }
                    420: 
                    421:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    422:        nIoMemAccessSize = SIZE_BYTE;
                    423:        nBusErrorAccesses = 0;
                    424: 
                    425:        IoMem[addr] = val;
                    426: 
                    427:        IoAccessCurrentAddress = addr;
                    428:        pInterceptWriteTable[addr-0xff8000]();        /* Call handler */
                    429: 
                    430:        /* Check if we wrote to a bus-error region */
                    431:        if (nBusErrorAccesses == 1)
                    432:        {
1.1.1.12! root      433:                M68000_BusError(addr, BUS_ERROR_WRITE, BUS_ERROR_SIZE_BYTE, BUS_ERROR_ACCESS_DATA);
1.1       root      434:        }
                    435: }
                    436: 
                    437: 
                    438: /*-----------------------------------------------------------------------*/
1.1.1.3   root      439: /**
                    440:  * Handle word write access to IO memory.
                    441:  */
1.1       root      442: void IoMem_wput(uaecptr addr, uae_u32 val)
                    443: {
                    444:        Uint32 idx;
                    445: 
                    446:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    447: 
1.1.1.11  root      448:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.w $%06x = $%04x pc=%x\n", addr, val&0x0ffff, M68000_GetPC());
1.1.1.6   root      449: 
1.1.1.5   root      450:        if (addr < 0x00ff8000 || !regs.s)
1.1       root      451:        {
                    452:                /* invalid memory addressing --> bus error */
1.1.1.12! root      453:                M68000_BusError(addr, BUS_ERROR_WRITE, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      454:                return;
                    455:        }
                    456:        if (addr > 0xfffffe)
                    457:        {
                    458:                fprintf(stderr, "Illegal IO memory access: IoMem_wput($%x)\n", addr);
                    459:                return;
                    460:        }
                    461: 
                    462:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    463:        nIoMemAccessSize = SIZE_WORD;
                    464:        nBusErrorAccesses = 0;
                    465: 
                    466:        IoMem_WriteWord(addr, val);
                    467:        idx = addr - 0xff8000;
                    468: 
                    469:        IoAccessCurrentAddress = addr;
                    470:        pInterceptWriteTable[idx]();                  /* Call 1st handler */
                    471: 
                    472:        if (pInterceptWriteTable[idx+1] != pInterceptWriteTable[idx])
                    473:        {
                    474:                IoAccessCurrentAddress = addr + 1;
                    475:                pInterceptWriteTable[idx+1]();            /* Call 2nd handler */
                    476:        }
                    477: 
                    478:        /* Check if we wrote to a bus-error region */
                    479:        if (nBusErrorAccesses == 2)
                    480:        {
1.1.1.12! root      481:                M68000_BusError(addr, BUS_ERROR_WRITE, BUS_ERROR_SIZE_WORD, BUS_ERROR_ACCESS_DATA);
1.1       root      482:        }
                    483: }
                    484: 
                    485: 
                    486: /*-----------------------------------------------------------------------*/
1.1.1.3   root      487: /**
                    488:  * Handle long-word write access to IO memory.
                    489:  */
1.1       root      490: void IoMem_lput(uaecptr addr, uae_u32 val)
                    491: {
                    492:        Uint32 idx;
1.1.1.12! root      493:        int n;
1.1       root      494: 
                    495:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    496: 
1.1.1.11  root      497:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.l $%06x = $%08x pc=%x\n", addr, val, M68000_GetPC());
1.1.1.6   root      498: 
1.1.1.5   root      499:        if (addr < 0xff8000 || !regs.s)
1.1       root      500:        {
                    501:                /* invalid memory addressing --> bus error */
1.1.1.12! root      502:                M68000_BusError(addr, BUS_ERROR_WRITE, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      503:                return;
                    504:        }
                    505:        if (addr > 0xfffffc)
                    506:        {
                    507:                fprintf(stderr, "Illegal IO memory access: IoMem_lput($%x)\n", addr);
                    508:                return;
                    509:        }
                    510: 
                    511:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    512:        nIoMemAccessSize = SIZE_LONG;
                    513:        nBusErrorAccesses = 0;
                    514: 
                    515:        IoMem_WriteLong(addr, val);
                    516:        idx = addr - 0xff8000;
                    517: 
                    518:        IoAccessCurrentAddress = addr;
1.1.1.12! root      519:        pInterceptWriteTable[idx]();                  /* Call first handler */
1.1       root      520: 
1.1.1.12! root      521:        for (n = 1; n < nIoMemAccessSize; n++)
1.1       root      522:        {
1.1.1.12! root      523:                if (pInterceptWriteTable[idx+n] != pInterceptWriteTable[idx+n-1])
        !           524:                {
        !           525:                        IoAccessCurrentAddress = addr + n;
        !           526:                        pInterceptWriteTable[idx+n]();   /* Call n-th handler */
        !           527:                }
1.1       root      528:        }
                    529: 
                    530:        /* Check if we wrote to a bus-error region */
                    531:        if (nBusErrorAccesses == 4)
                    532:        {
1.1.1.12! root      533:                M68000_BusError(addr, BUS_ERROR_WRITE, BUS_ERROR_SIZE_LONG, BUS_ERROR_ACCESS_DATA);
1.1       root      534:        }
                    535: }
                    536: 
                    537: 
                    538: /*-------------------------------------------------------------------------*/
1.1.1.3   root      539: /**
                    540:  * This handler will be called if a ST program tries to read from an address
                    541:  * that causes a bus error on a real ST. However, we can't call M68000_BusError()
                    542:  * directly: For example, a "move.b $ff8204,d0" triggers a bus error on a real ST,
                    543:  * while a "move.w $ff8204,d0" works! So we have to count the accesses to bus error
                    544:  * addresses and we only trigger a bus error later if the count matches the complete
                    545:  * access size (e.g. nBusErrorAccesses==4 for a long word access).
                    546:  */
1.1       root      547: void IoMem_BusErrorEvenReadAccess(void)
                    548: {
                    549:        nBusErrorAccesses += 1;
                    550:        IoMem[IoAccessCurrentAddress] = 0xff;
                    551: }
                    552: 
1.1.1.3   root      553: /**
                    554:  * We need two handler so that the IoMem_*get functions can distinguish
                    555:  * consecutive addresses.
                    556:  */
1.1       root      557: void IoMem_BusErrorOddReadAccess(void)
                    558: {
                    559:        nBusErrorAccesses += 1;
                    560:        IoMem[IoAccessCurrentAddress] = 0xff;
                    561: }
                    562: 
                    563: /*-------------------------------------------------------------------------*/
1.1.1.3   root      564: /**
                    565:  * Same as IoMem_BusErrorReadAccess() but for write access this time.
                    566:  */
1.1       root      567: void IoMem_BusErrorEvenWriteAccess(void)
                    568: {
                    569:        nBusErrorAccesses += 1;
                    570: }
                    571: 
1.1.1.3   root      572: /**
                    573:  * We need two handler so that the IoMem_*put functions can distinguish
                    574:  * consecutive addresses.
                    575:  */
1.1       root      576: void IoMem_BusErrorOddWriteAccess(void)
                    577: {
                    578:        nBusErrorAccesses += 1;
                    579: }
                    580: 
                    581: 
                    582: /*-------------------------------------------------------------------------*/
1.1.1.3   root      583: /**
                    584:  * This is the read handler for the IO memory locations without an assigned
                    585:  * IO register and which also do not generate a bus error. Reading from such
                    586:  * a register will return the result 0xff.
                    587:  */
1.1       root      588: void IoMem_VoidRead(void)
                    589: {
                    590:        Uint32 a;
                    591: 
                    592:        /* handler is probably called only once, so we have to take care of the neighbour "void IO registers" */
                    593:        for (a = IoAccessBaseAddress; a < IoAccessBaseAddress + nIoMemAccessSize; a++)
                    594:        {
                    595:                if (pInterceptReadTable[a - 0xff8000] == IoMem_VoidRead)
                    596:                {
                    597:                        IoMem[a] = 0xff;
                    598:                }
                    599:        }
                    600: }
                    601: 
                    602: /*-------------------------------------------------------------------------*/
1.1.1.3   root      603: /**
1.1.1.8   root      604:  * This is the same function as IoMem_VoidRead, but for IO registers that
                    605:  * return 0x00 instead of 0xff when read (this is the case for some video
                    606:  * registers on STE, Falcon, ...)
                    607:  */
                    608: void IoMem_VoidRead_00(void)
                    609: {
                    610:        Uint32 a;
                    611: 
                    612:        /* handler is probably called only once, so we have to take care of the neighbour "void IO registers" */
                    613:        for (a = IoAccessBaseAddress; a < IoAccessBaseAddress + nIoMemAccessSize; a++)
                    614:        {
                    615:                if (pInterceptReadTable[a - 0xff8000] == IoMem_VoidRead_00)
                    616:                {
                    617:                        IoMem[a] = 0x00;
                    618:                }
                    619:        }
                    620: }
                    621: 
                    622: /*-------------------------------------------------------------------------*/
                    623: /**
1.1.1.3   root      624:  * This is the write handler for the IO memory locations without an assigned
                    625:  * IO register and which also do not generate a bus error. We simply ignore
                    626:  * a write access to these registers.
                    627:  */
1.1       root      628: void IoMem_VoidWrite(void)
                    629: {
                    630:        /* Nothing... */
                    631: }
                    632: 
                    633: 
                    634: /*-------------------------------------------------------------------------*/
1.1.1.3   root      635: /**
                    636:  * A dummy function that does nothing at all - for memory regions that don't
                    637:  * need a special handler for read access.
                    638:  */
1.1       root      639: void IoMem_ReadWithoutInterception(void)
                    640: {
                    641:        /* Nothing... */
                    642: }
                    643: 
                    644: /*-------------------------------------------------------------------------*/
1.1.1.3   root      645: /**
                    646:  * A dummy function that does nothing at all - for memory regions that don't
                    647:  * need a special handler for write access.
                    648:  */
1.1       root      649: void IoMem_WriteWithoutInterception(void)
                    650: {
                    651:        /* Nothing... */
                    652: }

unix.superglobalmegacorp.com

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