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