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