Annotation of hatari/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. 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.2 ! root       31: const char IoMem_rcsid[] = "Hatari $Id: ioMem.c,v 1.12 2006/02/13 21:18:01 eerot Exp $";
1.1       root       32: 
                     33: #include "main.h"
                     34: #include "configuration.h"
                     35: #include "ioMem.h"
                     36: #include "ioMemTables.h"
                     37: #include "m68000.h"
                     38: #include "uae-cpu/sysdeps.h"
                     39: 
                     40: 
                     41: #define IOMEM_DEBUG 0
                     42: 
                     43: #if IOMEM_DEBUG
                     44: #define Dprintf(a) printf a
                     45: #else
                     46: #define Dprintf(a)
                     47: #endif
                     48: 
                     49: 
                     50: 
                     51: static void (*pInterceptReadTable[0x8000])(void);     /* Table with read access handlers */
                     52: static void (*pInterceptWriteTable[0x8000])(void);    /* Table with write access handlers */
                     53: 
                     54: int nIoMemAccessSize;                                 /* Set to 1, 2 or 4 according to byte, word or long word access */
                     55: Uint32 IoAccessBaseAddress;                           /* Stores the base address of the IO mem access */
1.1.1.2 ! root       56: static Uint32 IoAccessCurrentAddress;                 /* Current byte address while handling WORD and LONG accesses */
1.1       root       57: static int nBusErrorAccesses;                         /* Needed to count bus error accesses */
                     58: 
                     59: 
                     60: /*-----------------------------------------------------------------------*/
                     61: /*
                     62:   Fill a region with bus error handlers.
                     63: */
                     64: static void IoMem_SetBusErrorRegion(Uint32 startaddr, Uint32 endaddr)
                     65: {
                     66:        Uint32 a;
                     67: 
                     68:        for (a = startaddr; a <= endaddr; a++)
                     69:        {
                     70:                if (a & 1)
                     71:                {
                     72:                        pInterceptReadTable[a - 0xff8000] = IoMem_BusErrorOddReadAccess;     /* For 'read' */
                     73:                        pInterceptWriteTable[a - 0xff8000] = IoMem_BusErrorOddWriteAccess;   /* and 'write' */
                     74:                }
                     75:                else
                     76:                {
                     77:                        pInterceptReadTable[a - 0xff8000] = IoMem_BusErrorEvenReadAccess;    /* For 'read' */
                     78:                        pInterceptWriteTable[a - 0xff8000] = IoMem_BusErrorEvenWriteAccess;  /* and 'write' */
                     79:                }
                     80:        }
                     81: }
                     82: 
                     83: 
                     84: /*-----------------------------------------------------------------------*/
                     85: /*
                     86:   Create 'intercept' tables for hardware address access. Each 'intercept
                     87:   table is a list of 0x8000 pointers to a list of functions to call when
                     88:   that location in the ST's memory is accessed. 
                     89: */
                     90: void IoMem_Init(void)
                     91: {
                     92:        Uint32 addr;
                     93:        int i;
1.1.1.2 ! root       94:        const INTERCEPT_ACCESS_FUNC *pInterceptAccessFuncs = NULL;
1.1       root       95: 
                     96:        /* Set default IO access handler (-> bus error) */
                     97:        IoMem_SetBusErrorRegion(0xff8000, 0xffffff);
                     98: 
                     99:        switch (ConfigureParams.System.nMachineType)
                    100:        {
                    101:                case MACHINE_ST:  pInterceptAccessFuncs = IoMemTable_ST; break;
                    102:                case MACHINE_STE: pInterceptAccessFuncs = IoMemTable_STE; break;
1.1.1.2 ! root      103:                case MACHINE_TT: pInterceptAccessFuncs = IoMemTable_TT; break;
1.1       root      104:        }
                    105: 
                    106:        /* Now set the correct handlers */
                    107:        for (addr=0xff8000; addr <= 0xffffff; addr++)
                    108:        {
                    109:                /* Does this hardware location/span appear in our list of possible intercepted functions? */
                    110:                for (i=0; pInterceptAccessFuncs[i].Address != 0; i++)
                    111:                {
                    112:                        if (addr >= pInterceptAccessFuncs[i].Address
                    113:                            && addr < pInterceptAccessFuncs[i].Address+pInterceptAccessFuncs[i].SpanInBytes)
                    114:                        {
                    115:                                /* Security checks... */
                    116:                                if (pInterceptReadTable[addr-0xff8000] != IoMem_BusErrorEvenReadAccess && pInterceptReadTable[addr-0xff8000] != IoMem_BusErrorOddReadAccess)
                    117:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (R) already defined\n", addr);
                    118:                                if (pInterceptWriteTable[addr-0xff8000] != IoMem_BusErrorEvenWriteAccess && pInterceptWriteTable[addr-0xff8000] != IoMem_BusErrorOddWriteAccess)
                    119:                                        fprintf(stderr, "IoMem_Init: Warning: $%x (W) already defined\n", addr);
                    120: 
                    121:                                /* This location needs to be intercepted, so add entry to list */
                    122:                                pInterceptReadTable[addr-0xff8000] = pInterceptAccessFuncs[i].ReadFunc;
                    123:                                pInterceptWriteTable[addr-0xff8000] = pInterceptAccessFuncs[i].WriteFunc;
                    124:                        }
                    125:                }
                    126:        }
                    127: 
                    128:        /* Disable blitter? */
1.1.1.2 ! root      129:        if (!ConfigureParams.System.bBlitter && ConfigureParams.System.nMachineType != MACHINE_STE)
1.1       root      130:        {
                    131:                IoMem_SetBusErrorRegion(0xff8a00, 0xff8a3f);
                    132:        }
                    133: 
                    134:        /* Disable real time clock? */
                    135:        if (!ConfigureParams.System.bRealTimeClock)
                    136:        {
                    137:                for (addr = 0xfffc21; addr  <= 0xfffc3f; addr++)
                    138:                {
                    139:                        pInterceptReadTable[addr - 0xff8000] = IoMem_VoidRead;     /* For 'read' */
                    140:                        pInterceptWriteTable[addr - 0xff8000] = IoMem_VoidWrite;   /* and 'write' */
                    141:                }
                    142:        
                    143:        }
                    144: }
                    145: 
                    146: 
                    147: /*-----------------------------------------------------------------------*/
                    148: /*
                    149:   Uninitialize the IoMem code (currently unused).
                    150: */
                    151: void IoMem_UnInit(void)
                    152: {
                    153: }
                    154: 
                    155: 
                    156: /*-----------------------------------------------------------------------*/
                    157: /*
                    158:   Check if need to change our address as maybe a mirror register.
                    159:   Currently we only have a PSG mirror area.
                    160: */
                    161: static Uint32 IoMem_CheckMirrorAddresses(Uint32 addr)
                    162: {
                    163:        if (addr>=0xff8800 && addr<0xff8900)    /* Is a PSG mirror registers? */
                    164:                addr = 0xff8800 + (addr & 3);       /* Bring into 0xff8800-0xff8804 range */
                    165: 
                    166:        return addr;
                    167: }
                    168: 
                    169: 
                    170: 
                    171: /*-----------------------------------------------------------------------*/
                    172: /*
                    173:   Handle byte read access from IO memory.
                    174: */
                    175: uae_u32 IoMem_bget(uaecptr addr)
                    176: {
                    177:        Dprintf(("IoMem_bget($%x)\n", addr));
                    178: 
                    179:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    180: 
                    181:        if (addr < 0xff8000)
                    182:        {
                    183:                /* invalid memory addressing --> bus error */
                    184:                M68000_BusError(addr, 1);
                    185:                return -1;
                    186:        }
                    187: 
                    188:        IoAccessBaseAddress = addr;                   /* Store access location */
                    189:        nIoMemAccessSize = SIZE_BYTE;
                    190:        nBusErrorAccesses = 0;
                    191:        addr = IoMem_CheckMirrorAddresses(addr);
                    192: 
                    193:        IoAccessCurrentAddress = addr;
                    194:        pInterceptReadTable[addr-0xff8000]();         /* Call handler */
                    195: 
                    196:        /* Check if we read from a bus-error region */
                    197:        if (nBusErrorAccesses == 1)
                    198:        {
                    199:                M68000_BusError(addr, 1);
                    200:                return -1;
                    201:        }
                    202: 
                    203:        return IoMem[addr];
                    204: }
                    205: 
                    206: 
                    207: /*-----------------------------------------------------------------------*/
                    208: /*
                    209:   Handle word read access from IO memory.
                    210: */
                    211: uae_u32 IoMem_wget(uaecptr addr)
                    212: {
                    213:        Uint32 idx;
                    214: 
                    215:        Dprintf(("IoMem_wget($%x)\n", addr));
                    216: 
                    217:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    218: 
                    219:        if (addr < 0xff8000)
                    220:        {
                    221:                /* invalid memory addressing --> bus error */
                    222:                M68000_BusError(addr, 1);
                    223:                return -1;
                    224:        }
                    225:        if (addr > 0xfffffe)
                    226:        {
                    227:                fprintf(stderr, "Illegal IO memory access: IoMem_wget($%x)\n", addr);
                    228:                return -1;
                    229:        }
                    230: 
                    231:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    232:        nIoMemAccessSize = SIZE_WORD;
                    233:        nBusErrorAccesses = 0;
                    234:        addr = IoMem_CheckMirrorAddresses(addr);
                    235:        idx = addr - 0xff8000;
                    236: 
                    237:        IoAccessCurrentAddress = addr;
                    238:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    239: 
                    240:        if (pInterceptReadTable[idx+1] != pInterceptReadTable[idx])
                    241:        {
                    242:                IoAccessCurrentAddress = addr + 1;
                    243:                pInterceptReadTable[idx+1]();             /* Call 2nd handler */
                    244:        }
                    245: 
                    246:        /* Check if we completely read from a bus-error region */
                    247:        if (nBusErrorAccesses == 2)
                    248:        {
                    249:                M68000_BusError(addr, 1);
                    250:                return -1;
                    251:        }
                    252: 
                    253:        return IoMem_ReadWord(addr);
                    254: }
                    255: 
                    256: 
                    257: /*-----------------------------------------------------------------------*/
                    258: /*
                    259:   Handle long-word read access from IO memory.
                    260: */
                    261: uae_u32 IoMem_lget(uaecptr addr)
                    262: {
                    263:        Uint32 idx;
                    264: 
                    265:        Dprintf(("IoMem_lget($%x)\n", addr));
                    266: 
                    267:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    268: 
                    269:        if (addr < 0xff8000)
                    270:        {
                    271:                /* invalid memory addressing --> bus error */
                    272:                M68000_BusError(addr, 1);
                    273:                return -1;
                    274:        }
                    275:        if (addr > 0xfffffc)
                    276:        {
                    277:                fprintf(stderr, "Illegal IO memory access: IoMem_lget($%x)\n", addr);
                    278:                return -1;
                    279:        }
                    280: 
                    281:        IoAccessBaseAddress = addr;                   /* Store for exception frame */
                    282:        nIoMemAccessSize = SIZE_LONG;
                    283:        nBusErrorAccesses = 0;
                    284:        addr = IoMem_CheckMirrorAddresses(addr);
                    285:        idx = addr - 0xff8000;
                    286: 
                    287:        IoAccessCurrentAddress = addr;
                    288:        pInterceptReadTable[idx]();                   /* Call 1st handler */
                    289: 
                    290:        if (pInterceptReadTable[idx+1] != pInterceptReadTable[idx])
                    291:        {
                    292:                IoAccessCurrentAddress = addr + 1;
                    293:                pInterceptReadTable[idx+1]();             /* Call 2nd handler */
                    294:        }
                    295: 
                    296:        if (pInterceptReadTable[idx+2] != pInterceptReadTable[idx+1])
                    297:        {
                    298:                IoAccessCurrentAddress = addr + 2;
                    299:                pInterceptReadTable[idx+2]();             /* Call 3rd handler */
                    300:        }
                    301: 
                    302:        if (pInterceptReadTable[idx+3] != pInterceptReadTable[idx+2])
                    303:        {
                    304:                IoAccessCurrentAddress = addr + 3;
                    305:                pInterceptReadTable[idx+3]();             /* Call 4th handler */
                    306:        }
                    307: 
                    308:        /* Check if we completely read from a bus-error region */
                    309:        if (nBusErrorAccesses == 4)
                    310:        {
                    311:                M68000_BusError(addr, 1);
                    312:                return -1;
                    313:        }
                    314: 
                    315:        return IoMem_ReadLong(addr);
                    316: }
                    317: 
                    318: 
                    319: /*-----------------------------------------------------------------------*/
                    320: /*
                    321:   Handle byte write access to IO memory.
                    322: */
                    323: void IoMem_bput(uaecptr addr, uae_u32 val)
                    324: {
                    325:        Dprintf(("IoMem_bput($%x, $%x)\n", addr, val));
                    326: 
                    327:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    328: 
                    329:        if (addr < 0xff8000)
                    330:        {
                    331:                /* invalid memory addressing --> bus error */
                    332:                M68000_BusError(addr, 0);
                    333:                return;
                    334:        }
                    335: 
                    336:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    337:        nIoMemAccessSize = SIZE_BYTE;
                    338:        nBusErrorAccesses = 0;
                    339:        addr = IoMem_CheckMirrorAddresses(addr);
                    340: 
                    341:        IoMem[addr] = val;
                    342: 
                    343:        IoAccessCurrentAddress = addr;
                    344:        pInterceptWriteTable[addr-0xff8000]();        /* Call handler */
                    345: 
                    346:        /* Check if we wrote to a bus-error region */
                    347:        if (nBusErrorAccesses == 1)
                    348:        {
                    349:                M68000_BusError(addr, 0);
                    350:        }
                    351: }
                    352: 
                    353: 
                    354: /*-----------------------------------------------------------------------*/
                    355: /*
                    356:   Handle word write access to IO memory.
                    357: */
                    358: void IoMem_wput(uaecptr addr, uae_u32 val)
                    359: {
                    360:        Uint32 idx;
                    361: 
                    362:        Dprintf(("IoMem_wput($%x, $%x)\n", addr, val));
                    363: 
                    364:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    365: 
                    366:        if (addr < 0x00ff8000)
                    367:        {
                    368:                /* invalid memory addressing --> bus error */
                    369:                M68000_BusError(addr, 0);
                    370:                return;
                    371:        }
                    372:        if (addr > 0xfffffe)
                    373:        {
                    374:                fprintf(stderr, "Illegal IO memory access: IoMem_wput($%x)\n", addr);
                    375:                return;
                    376:        }
                    377: 
                    378:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    379:        nIoMemAccessSize = SIZE_WORD;
                    380:        nBusErrorAccesses = 0;
                    381:        addr = IoMem_CheckMirrorAddresses(addr);
                    382: 
                    383:        IoMem_WriteWord(addr, val);
                    384:        idx = addr - 0xff8000;
                    385: 
                    386:        IoAccessCurrentAddress = addr;
                    387:        pInterceptWriteTable[idx]();                  /* Call 1st handler */
                    388: 
                    389:        if (pInterceptWriteTable[idx+1] != pInterceptWriteTable[idx])
                    390:        {
                    391:                IoAccessCurrentAddress = addr + 1;
                    392:                pInterceptWriteTable[idx+1]();            /* Call 2nd handler */
                    393:        }
                    394: 
                    395:        /* Check if we wrote to a bus-error region */
                    396:        if (nBusErrorAccesses == 2)
                    397:        {
                    398:                M68000_BusError(addr, 0);
                    399:        }
                    400: }
                    401: 
                    402: 
                    403: /*-----------------------------------------------------------------------*/
                    404: /*
                    405:   Handle long-word write access to IO memory.
                    406: */
                    407: void IoMem_lput(uaecptr addr, uae_u32 val)
                    408: {
                    409:        Uint32 idx;
                    410: 
                    411:        Dprintf(("IoMem_lput($%x, $%x)\n", addr, val));
                    412: 
                    413:        addr &= 0x00ffffff;                           /* Use a 24 bit address */
                    414: 
                    415:        if (addr < 0xff8000)
                    416:        {
                    417:                /* invalid memory addressing --> bus error */
                    418:                M68000_BusError(addr, 0);
                    419:                return;
                    420:        }
                    421:        if (addr > 0xfffffc)
                    422:        {
                    423:                fprintf(stderr, "Illegal IO memory access: IoMem_lput($%x)\n", addr);
                    424:                return;
                    425:        }
                    426: 
                    427:        IoAccessBaseAddress = addr;                   /* Store for exception frame, just in case */
                    428:        nIoMemAccessSize = SIZE_LONG;
                    429:        nBusErrorAccesses = 0;
                    430:        addr = IoMem_CheckMirrorAddresses(addr);
                    431: 
                    432:        IoMem_WriteLong(addr, val);
                    433:        idx = addr - 0xff8000;
                    434: 
                    435:        IoAccessCurrentAddress = addr;
                    436:        pInterceptWriteTable[idx]();                  /* Call handler */
                    437: 
                    438:        if (pInterceptWriteTable[idx+1] != pInterceptWriteTable[idx])
                    439:        {
                    440:                IoAccessCurrentAddress = addr + 1;
                    441:                pInterceptWriteTable[idx+1]();            /* Call 2nd handler */
                    442:        }
                    443: 
                    444:        if (pInterceptWriteTable[idx+2] != pInterceptWriteTable[idx+1])
                    445:        {
                    446:                IoAccessCurrentAddress = addr + 2;
                    447:                pInterceptWriteTable[idx+2]();            /* Call 3rd handler */
                    448:        }
                    449: 
                    450:        if (pInterceptWriteTable[idx+3] != pInterceptWriteTable[idx+2])
                    451:        {
                    452:                IoAccessCurrentAddress = addr + 3;
                    453:                pInterceptWriteTable[idx+3]();            /* Call 4th handler */
                    454:        }
                    455: 
                    456:        /* Check if we wrote to a bus-error region */
                    457:        if (nBusErrorAccesses == 4)
                    458:        {
                    459:                M68000_BusError(addr, 0);
                    460:        }
                    461: }
                    462: 
                    463: 
                    464: /*-------------------------------------------------------------------------*/
                    465: /*
                    466:   This handler will be called if a ST program tries to read from an address
                    467:   that causes a bus error on a real ST. However, we can't call M68000_BusError()
                    468:   directly: For example, a "move.b $ff8204,d0" triggers a bus error on a real ST,
                    469:   while a "move.w $ff8204,d0" works! So we have to count the accesses to bus error
                    470:   addresses and we only trigger a bus error later if the count matches the complete
                    471:   access size (e.g. nBusErrorAccesses==4 for a long word access).
                    472: */
                    473: void IoMem_BusErrorEvenReadAccess(void)
                    474: {
                    475:        nBusErrorAccesses += 1;
                    476:        IoMem[IoAccessCurrentAddress] = 0xff;
                    477: }
                    478: 
                    479: /*
                    480:   We need two handler so that the IoMem_*get functions can distinguish
                    481:   consecutive addresses.
                    482: */
                    483: void IoMem_BusErrorOddReadAccess(void)
                    484: {
                    485:        nBusErrorAccesses += 1;
                    486:        IoMem[IoAccessCurrentAddress] = 0xff;
                    487: }
                    488: 
                    489: /*-------------------------------------------------------------------------*/
                    490: /*
                    491:   Same as IoMem_BusErrorReadAccess() but for write access this time.
                    492: */
                    493: void IoMem_BusErrorEvenWriteAccess(void)
                    494: {
                    495:        nBusErrorAccesses += 1;
                    496: }
                    497: 
                    498: /*
                    499:   We need two handler so that the IoMem_*put functions can distinguish
                    500:   consecutive addresses.
                    501: */
                    502: void IoMem_BusErrorOddWriteAccess(void)
                    503: {
                    504:        nBusErrorAccesses += 1;
                    505: }
                    506: 
                    507: 
                    508: /*-------------------------------------------------------------------------*/
                    509: /*
                    510:   This is the read handler for the IO memory locations without an assigned
                    511:   IO register and which also do not generate a bus error. Reading from such
                    512:   a register will return the result 0xff.
                    513: */
                    514: void IoMem_VoidRead(void)
                    515: {
                    516:        Uint32 a;
                    517: 
                    518:        /* handler is probably called only once, so we have to take care of the neighbour "void IO registers" */
                    519:        for (a = IoAccessBaseAddress; a < IoAccessBaseAddress + nIoMemAccessSize; a++)
                    520:        {
                    521:                if (pInterceptReadTable[a - 0xff8000] == IoMem_VoidRead)
                    522:                {
                    523:                        IoMem[a] = 0xff;
                    524:                }
                    525:        }
                    526: }
                    527: 
                    528: /*-------------------------------------------------------------------------*/
                    529: /*
                    530:   This is the write handler for the IO memory locations without an assigned
                    531:   IO register and which also do not generate a bus error. We simply ignore
                    532:   a write access to these registers.
                    533: */
                    534: void IoMem_VoidWrite(void)
                    535: {
                    536:        /* Nothing... */
                    537: }
                    538: 
                    539: 
                    540: /*-------------------------------------------------------------------------*/
                    541: /*
                    542:   A dummy function that does nothing at all - for memory regions that don't
                    543:   need a special handler for read access.
                    544: */
                    545: void IoMem_ReadWithoutInterception(void)
                    546: {
                    547:        /* Nothing... */
                    548: }
                    549: 
                    550: /*-------------------------------------------------------------------------*/
                    551: /*
                    552:   A dummy function that does nothing at all - for memory regions that don't
                    553:   need a special handler for write access.
                    554: */
                    555: void IoMem_WriteWithoutInterception(void)
                    556: {
                    557:        /* Nothing... */
                    558: }

unix.superglobalmegacorp.com

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