|
|
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.