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

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

unix.superglobalmegacorp.com

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