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