Annotation of previous/src/ioMem.c, revision 1.1.1.2

1.1       root        1: /*
                      2:   Hatari - ioMem.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
                      7:   This is where we intercept read/writes to/from the hardware. 
                      8: */
                      9: const char IoMem_fileid[] = "Hatari ioMem.c : " __DATE__ " " __TIME__;
                     10: 
                     11: #include "main.h"
                     12: #include "configuration.h"
                     13: #include "ioMem.h"
                     14: #include "ioMemTables.h"
1.1.1.2 ! root       15: #include "memorySnapShot.h"
1.1       root       16: #include "m68000.h"
                     17: #include "sysdeps.h"
                     18: 
                     19: #define IO_SEG_MASK 0x0001FFFF
                     20: #define IO_MASK 0x0001FFFF
                     21: #define IO_SIZE 0x00020000
                     22: 
                     23: static void (*pInterceptReadTable[IO_SIZE])(void);     /* Table with read access handlers */
                     24: static void (*pInterceptWriteTable[IO_SIZE])(void);    /* Table with write access handlers */
                     25: 
                     26: int nIoMemAccessSize;                                 /* Set to 1, 2 or 4 according to byte, word or long word access */
                     27: Uint32 IoAccessBaseAddress;                           /* Stores the base address of the IO mem access */
                     28: Uint32 IoAccessCurrentAddress;                        /* Current byte address while handling WORD and LONG accesses */
                     29: static int nBusErrorAccesses;                         /* Needed to count bus error accesses */
                     30: 
                     31: 
                     32: /*-----------------------------------------------------------------------*/
                     33: /**
                     34:  * Fill a region with bus error handlers.
                     35:  */
                     36: static void IoMem_SetBusErrorRegion(Uint32 startaddr, Uint32 endaddr)
                     37: {
                     38:        Uint32 a;
                     39: 
                     40:        for (a = startaddr; a <= endaddr; a++)
                     41:        {
                     42:                if (a & 1)
                     43:                {
                     44:                        pInterceptReadTable[a & 0x1FFFF] = IoMem_BusErrorOddReadAccess;     /* For 'read' */
                     45:                        pInterceptWriteTable[a & 0x1FFFF] = IoMem_BusErrorOddWriteAccess;   /* and 'write' */
                     46:                }
                     47:                else
                     48:                {
                     49:                        pInterceptReadTable[a & 0x1FFFF] = IoMem_BusErrorEvenReadAccess;    /* For 'read' */
                     50:                        pInterceptWriteTable[a & 0x1FFFF] = IoMem_BusErrorEvenWriteAccess;  /* and 'write' */
                     51:                }
                     52:        }
                     53: }
                     54: 
                     55: 
                     56: /*-----------------------------------------------------------------------*/
                     57: /**
                     58:  * Create 'intercept' tables for hardware address access. Each 'intercept
                     59:  */
                     60: void IoMem_Init(void)
                     61: {
                     62:        Uint32 addr;
                     63:        int i;
                     64:        const INTERCEPT_ACCESS_FUNC *pInterceptAccessFuncs = NULL;
                     65: 
                     66:        /* Set default IO access handler (-> bus error) */
                     67:        IoMem_SetBusErrorRegion(0x02000000, 0x0201FFFF);
                     68: 
                     69:        pInterceptAccessFuncs=IoMemTable_NEXT;
                     70: 
                     71:        /* Now set the correct handlers */
                     72:        for (addr=0x02000000; addr <= 0x0201FFFF; addr++)
                     73:        {
                     74:                /* Does this hardware location/span appear in our list of possible intercepted functions? */
                     75:                for (i=0; pInterceptAccessFuncs[i].Address != 0; i++)
                     76:                {
                     77:                        if (addr >= pInterceptAccessFuncs[i].Address
                     78:                            && addr < pInterceptAccessFuncs[i].Address+pInterceptAccessFuncs[i].SpanInBytes)
                     79:                        {
                     80:                                /* Security checks... */
                     81:                                if (pInterceptReadTable[addr & 0x1FFFF] != IoMem_BusErrorEvenReadAccess && pInterceptReadTable[addr&0x1FFFF] != IoMem_BusErrorOddReadAccess)
                     82:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (R) already defined\n", addr);
                     83:                                if (pInterceptWriteTable[addr& 0x1FFFF] != IoMem_BusErrorEvenWriteAccess && pInterceptWriteTable[addr&0x1FFFF] != IoMem_BusErrorOddWriteAccess)
                     84:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (W) already defined\n", addr);
                     85: 
                     86:                                /* This location needs to be intercepted, so add entry to list */
                     87:                                pInterceptReadTable[addr& 0x1FFFF] = pInterceptAccessFuncs[i].ReadFunc;
                     88:                                pInterceptWriteTable[addr& 0x1FFFF] = pInterceptAccessFuncs[i].WriteFunc;
                     89:                        }
                     90:                }
                     91:        }
                     92: 
                     93: 
                     94: }
                     95: 
                     96: 
                     97: /*-----------------------------------------------------------------------*/
                     98: /**
                     99:  * Uninitialize the IoMem code (currently unused).
                    100:  */
                    101: void IoMem_UnInit(void)
                    102: {
                    103: }
                    104: 
                    105: 
                    106: /*-----------------------------------------------------------------------*/
                    107: /**
                    108:  * Handle byte read access from IO memory.
                    109:  */
                    110: uae_u32 IoMem_bget(uaecptr addr)
                    111: {
                    112:        Uint8 val;
                    113: 
                    114:        if ((addr & IO_SEG_MASK) >= IO_SIZE)
                    115:        {
                    116:                /* invalid memory addressing --> bus error */
1.1.1.2 ! root      117:                M68000_BusError(addr, BUS_ERROR_READ);
1.1       root      118:                return -1;
                    119:        }
                    120: 
                    121:        IoAccessBaseAddress = addr;                   /* Store access location */
                    122:        nIoMemAccessSize = SIZE_BYTE;
                    123:        nBusErrorAccesses = 0;
                    124: 
                    125:        IoAccessCurrentAddress = addr;
                    126:        pInterceptReadTable[addr & IO_SEG_MASK]();         /* Call handler */
                    127: 
                    128:        /* Check if we read from a bus-error region */
                    129:        if (nBusErrorAccesses == 1)
                    130:        {
1.1.1.2 ! root      131:                M68000_BusError(addr, BUS_ERROR_READ);
1.1       root      132:                return -1;
                    133:        }
                    134: 
                    135:        val = IoMem[addr & IO_SEG_MASK];
                    136: 
                    137:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.b $%06x = $%02x\n", addr, val);
                    138: 
                    139:        return val;
                    140: }
                    141: 
                    142: 
                    143: /*-----------------------------------------------------------------------*/
                    144: /**
                    145:  * Handle word read access from IO memory.
                    146:  */
                    147: uae_u32 IoMem_wget(uaecptr addr)
                    148: {
                    149:        Uint32 idx;
                    150:        Uint16 val;
                    151: 
                    152: 
                    153:        if ((addr & IO_SEG_MASK) >= IO_SIZE)
                    154:        {
                    155:                /* invalid memory addressing --> bus error */
1.1.1.2 ! root      156:                M68000_BusError(addr, BUS_ERROR_READ);
1.1       root      157:                return -1;
                    158:        }
                    159: 
                    160:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    161:        nIoMemAccessSize = SIZE_WORD;
                    162:        nBusErrorAccesses = 0;
                    163:        idx = addr & IO_SEG_MASK;
                    164: 
                    165:        IoAccessCurrentAddress = addr;
                    166:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    167: 
                    168:        if (pInterceptReadTable[idx+1] != pInterceptReadTable[idx])
                    169:        {
                    170:                IoAccessCurrentAddress = addr + 1;
                    171:                pInterceptReadTable[idx+1]();             /* Call 2nd handler */
                    172:        }
                    173: 
                    174:        /* Check if we completely read from a bus-error region */
                    175:        if (nBusErrorAccesses == 2)
                    176:        {
1.1.1.2 ! root      177:                M68000_BusError(addr, BUS_ERROR_READ);
1.1       root      178:                return -1;
                    179:        }
                    180: 
                    181:        val = IoMem_ReadWord(addr);
                    182: 
                    183:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.w $%06x = $%04x\n", addr, val);
                    184: 
                    185:        return val;
                    186: }
                    187: 
                    188: 
                    189: /*-----------------------------------------------------------------------*/
                    190: /**
                    191:  * Handle long-word read access from IO memory.
                    192:  */
                    193: uae_u32 IoMem_lget(uaecptr addr)
                    194: {
                    195:        Uint32 idx;
                    196:        Uint32 val;
                    197: 
                    198: 
                    199:        if ((addr & IO_SEG_MASK) >= IO_SIZE)
                    200:        {
                    201:                /* invalid memory addressing --> bus error */
1.1.1.2 ! root      202:                M68000_BusError(addr, BUS_ERROR_READ);
1.1       root      203:                return -1;
                    204:        }
                    205: 
                    206:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    207:        nIoMemAccessSize = SIZE_LONG;
                    208:        nBusErrorAccesses = 0;
                    209:        idx = addr & IO_SEG_MASK;
                    210: 
                    211:        IoAccessCurrentAddress = addr;
                    212:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    213: 
                    214:        if (pInterceptReadTable[idx+1] != pInterceptReadTable[idx])
                    215:        {
                    216:                IoAccessCurrentAddress = addr + 1;
                    217:                pInterceptReadTable[idx+1]();             /* Call 2nd handler */
                    218:        }
                    219: 
                    220:        if (pInterceptReadTable[idx+2] != pInterceptReadTable[idx+1])
                    221:        {
                    222:                IoAccessCurrentAddress = addr + 2;
                    223:                pInterceptReadTable[idx+2]();             /* Call 3rd handler */
                    224:        }
                    225: 
                    226:        if (pInterceptReadTable[idx+3] != pInterceptReadTable[idx+2])
                    227:        {
                    228:                IoAccessCurrentAddress = addr + 3;
                    229:                pInterceptReadTable[idx+3]();             /* Call 4th handler */
                    230:        }
                    231: 
                    232:        /* Check if we completely read from a bus-error region */
                    233:        if (nBusErrorAccesses == 4)
                    234:        {
1.1.1.2 ! root      235:                M68000_BusError(addr, BUS_ERROR_READ);
1.1       root      236:                return -1;
                    237:        }
                    238: 
                    239:        val = IoMem_ReadLong(addr);
                    240: 
                    241:        LOG_TRACE(TRACE_IOMEM_RD, "IO read.l $%06x = $%08x\n", addr, val);
                    242: 
                    243:        return val;
                    244: }
                    245: 
                    246: 
                    247: /*-----------------------------------------------------------------------*/
                    248: /**
                    249:  * Handle byte write access to IO memory.
                    250:  */
                    251: void IoMem_bput(uaecptr addr, uae_u32 val)
                    252: {
                    253: 
                    254:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.b $%06x = $%02x\n", addr, val&0x0ff);
                    255: 
                    256:        if ((addr & IO_SEG_MASK) >= IO_SIZE)
                    257:        {
                    258:                /* invalid memory addressing --> bus error */
1.1.1.2 ! root      259:                M68000_BusError(addr, BUS_ERROR_WRITE);
1.1       root      260:                return;
                    261:        }
                    262: 
                    263:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    264:        nIoMemAccessSize = SIZE_BYTE;
                    265:        nBusErrorAccesses = 0;
                    266: 
                    267:        IoMem[addr & IO_SEG_MASK] = val;
                    268: 
                    269:        IoAccessCurrentAddress = addr;
                    270:        pInterceptWriteTable[addr & IO_SEG_MASK]();        /* Call handler */
                    271: 
                    272:        /* Check if we wrote to a bus-error region */
                    273:        if (nBusErrorAccesses == 1)
                    274:        {
1.1.1.2 ! root      275:                M68000_BusError(addr, BUS_ERROR_WRITE);
1.1       root      276:        }
                    277: }
                    278: 
                    279: 
                    280: /*-----------------------------------------------------------------------*/
                    281: /**
                    282:  * Handle word write access to IO memory.
                    283:  */
                    284: void IoMem_wput(uaecptr addr, uae_u32 val)
                    285: {
                    286:        Uint32 idx;
                    287: 
                    288: 
                    289:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.w $%06x = $%04x\n", addr, val&0xffff);
                    290: 
                    291:        if ((addr & IO_SEG_MASK) >= IO_SIZE)
                    292:        {
                    293:                /* invalid memory addressing --> bus error */
1.1.1.2 ! root      294:                M68000_BusError(addr, BUS_ERROR_WRITE);
1.1       root      295:                return;
                    296:        }
                    297: 
                    298:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    299:        nIoMemAccessSize = SIZE_WORD;
                    300:        nBusErrorAccesses = 0;
                    301: 
                    302:        IoMem_WriteWord(addr, val);
                    303:        idx = addr & IO_SEG_MASK;
                    304: 
                    305:        IoAccessCurrentAddress = addr;
                    306:        pInterceptWriteTable[idx]();                  /* Call 1st handler */
                    307: 
                    308:        if (pInterceptWriteTable[idx+1] != pInterceptWriteTable[idx])
                    309:        {
                    310:                IoAccessCurrentAddress = addr + 1;
                    311:                pInterceptWriteTable[idx+1]();            /* Call 2nd handler */
                    312:        }
                    313: 
                    314:        /* Check if we wrote to a bus-error region */
                    315:        if (nBusErrorAccesses == 2)
                    316:        {
1.1.1.2 ! root      317:                M68000_BusError(addr, BUS_ERROR_WRITE);
1.1       root      318:        }
                    319: }
                    320: 
                    321: 
                    322: /*-----------------------------------------------------------------------*/
                    323: /**
                    324:  * Handle long-word write access to IO memory.
                    325:  */
                    326: void IoMem_lput(uaecptr addr, uae_u32 val)
                    327: {
                    328:        Uint32 idx;
                    329: 
                    330:        LOG_TRACE(TRACE_IOMEM_WR, "IO write.l $%06x = $%08x\n", addr, val);
                    331: 
                    332:        if ((addr & IO_SEG_MASK) >= IO_SIZE)
                    333:        {
                    334:                /* invalid memory addressing --> bus error */
1.1.1.2 ! root      335:                M68000_BusError(addr, BUS_ERROR_WRITE);
1.1       root      336:                return;
                    337:        }
                    338: 
                    339:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    340:        nIoMemAccessSize = SIZE_LONG;
                    341:        nBusErrorAccesses = 0;
                    342: 
                    343:        IoMem_WriteLong(addr, val);
                    344:        idx = addr & IO_SEG_MASK;
                    345: 
                    346:        IoAccessCurrentAddress = addr;
                    347:        pInterceptWriteTable[idx]();                  /* Call handler */
                    348: 
                    349:        if (pInterceptWriteTable[idx+1] != pInterceptWriteTable[idx])
                    350:        {
                    351:                IoAccessCurrentAddress = addr + 1;
                    352:                pInterceptWriteTable[idx+1]();            /* Call 2nd handler */
                    353:        }
                    354: 
                    355:        if (pInterceptWriteTable[idx+2] != pInterceptWriteTable[idx+1])
                    356:        {
                    357:                IoAccessCurrentAddress = addr + 2;
                    358:                pInterceptWriteTable[idx+2]();            /* Call 3rd handler */
                    359:        }
                    360: 
                    361:        if (pInterceptWriteTable[idx+3] != pInterceptWriteTable[idx+2])
                    362:        {
                    363:                IoAccessCurrentAddress = addr + 3;
                    364:                pInterceptWriteTable[idx+3]();            /* Call 4th handler */
                    365:        }
                    366: 
                    367:        /* Check if we wrote to a bus-error region */
                    368:        if (nBusErrorAccesses == 4)
                    369:        {
1.1.1.2 ! root      370:                M68000_BusError(addr, BUS_ERROR_WRITE);
1.1       root      371:        }
                    372: }
                    373: 
                    374: 
                    375: /*-------------------------------------------------------------------------*/
                    376: /**
                    377:  * This handler will be called if a program tries to read from an address
                    378:  * that causes a bus error on a real machine. However, we can't call M68000_BusError()
                    379:  * directly: For example, a "move.b $ff8204,d0" triggers a bus error on a real ST,
                    380:  * while a "move.w $ff8204,d0" works! So we have to count the accesses to bus error
                    381:  * addresses and we only trigger a bus error later if the count matches the complete
                    382:  * access size (e.g. nBusErrorAccesses==4 for a long word access).
                    383:  */
                    384: void IoMem_BusErrorEvenReadAccess(void)
                    385: {
                    386:        nBusErrorAccesses += 1;
                    387:        IoMem[IoAccessCurrentAddress& IO_SEG_MASK] = 0xff;
                    388: }
                    389: 
                    390: /**
                    391:  * We need two handler so that the IoMem_*get functions can distinguish
                    392:  * consecutive addresses.
                    393:  */
                    394: void IoMem_BusErrorOddReadAccess(void)
                    395: {
                    396:        nBusErrorAccesses += 1;
                    397:        IoMem[IoAccessCurrentAddress& IO_SEG_MASK] = 0xff;
                    398: }
                    399: 
                    400: /*-------------------------------------------------------------------------*/
                    401: /**
                    402:  * Same as IoMem_BusErrorReadAccess() but for write access this time.
                    403:  */
                    404: void IoMem_BusErrorEvenWriteAccess(void)
                    405: {
                    406:        nBusErrorAccesses += 1;
                    407: }
                    408: 
                    409: /**
                    410:  * We need two handler so that the IoMem_*put functions can distinguish
                    411:  * consecutive addresses.
                    412:  */
                    413: void IoMem_BusErrorOddWriteAccess(void)
                    414: {
                    415:        nBusErrorAccesses += 1;
                    416: }
                    417: 
                    418: 
                    419: /*-------------------------------------------------------------------------*/
                    420: /**
                    421:  * This is the read handler for the IO memory locations without an assigned
                    422:  * IO register and which also do not generate a bus error. Reading from such
                    423:  * a register will return the result 0xff.
                    424:  */
                    425: void IoMem_VoidRead(void)
                    426: {
                    427:        Uint32 a;
                    428: 
                    429:        /* handler is probably called only once, so we have to take care of the neighbour "void IO registers" */
                    430:        for (a = IoAccessBaseAddress; a < IoAccessBaseAddress + nIoMemAccessSize; a++)
                    431:        {
                    432:                if (pInterceptReadTable[a & IO_SEG_MASK] == IoMem_VoidRead)
                    433:                {
                    434:                        IoMem[a & IO_SEG_MASK] = 0xff;
                    435:                }
                    436:        }
                    437: }
                    438: 
                    439: /*-------------------------------------------------------------------------*/
                    440: /**
1.1.1.2 ! root      441:  * This is the same function as IoMem_VoidRead, but for IO registers that
        !           442:  * return 0x00 instead of 0xff when read (this is the case for some video
        !           443:  * registers on STE, Falcon, ...)
        !           444:  */
        !           445: void IoMem_VoidRead_00(void)
        !           446: {
        !           447:     Uint32 a;
        !           448: 
        !           449:     /* handler is probably called only once, so we have to take care of the neighbour "void IO registers" */
        !           450:     for (a = IoAccessBaseAddress; a < IoAccessBaseAddress + nIoMemAccessSize; a++)
        !           451:     {
        !           452:         if (pInterceptReadTable[a - 0xff8000] == IoMem_VoidRead_00)
        !           453:         {
        !           454:             IoMem[a] = 0x00;
        !           455:         }
        !           456:     }
        !           457: }
        !           458: 
        !           459: /*-------------------------------------------------------------------------*/
        !           460: /**
1.1       root      461:  * This is the write handler for the IO memory locations without an assigned
                    462:  * IO register and which also do not generate a bus error. We simply ignore
                    463:  * a write access to these registers.
                    464:  */
                    465: void IoMem_VoidWrite(void)
                    466: {
                    467:        /* Nothing... */
                    468: }
                    469: 
                    470: 
                    471: /*-------------------------------------------------------------------------*/
                    472: /**
                    473:  * A dummy function that does nothing at all - for memory regions that don't
                    474:  * need a special handler for read access.
                    475:  */
                    476: void IoMem_ReadWithoutInterception(void)
                    477: {
                    478:        /* Nothing... */
                    479: }
                    480: 
                    481: /*-------------------------------------------------------------------------*/
                    482: /**
                    483:  * A dummy function that does nothing at all - for memory regions that don't
                    484:  * need a special handler for write access.
                    485:  */
                    486: void IoMem_WriteWithoutInterception(void)
                    487: {
                    488:        /* Nothing... */
                    489: }
                    490: 
                    491: /*-------------------------------------------------------------------------*/
                    492: /**
                    493:  * A dummy function that does nothing at all - for memory regions that don't
                    494:  * need a special handler for read access.
                    495:  */
                    496: void IoMem_ReadWithoutInterceptionButTrace(void)
                    497: {
                    498:        Log_Printf(LOG_WARN,"IO read at $%08x PC=$%08x\n", IoAccessCurrentAddress,regs.pc);
                    499: }
                    500: 
                    501: /*-------------------------------------------------------------------------*/
                    502: /**
                    503:  * A dummy function that does nothing at all - for memory regions that don't
                    504:  * need a special handler for write access.
                    505:  */
                    506: void IoMem_WriteWithoutInterceptionButTrace(void)
                    507: {
                    508:        Log_Printf(LOG_WARN,"IO write at $%08x val=%02x PC=$%08x\n", IoAccessCurrentAddress,IoMem[IoAccessCurrentAddress & IO_SEG_MASK],regs.pc);
                    509: }

unix.superglobalmegacorp.com

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