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

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

unix.superglobalmegacorp.com

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