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