|
|
1.1.1.2 root 1: /*
2: * cpummu.h - MMU emulation
3: *
4: * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS)
5: *
6: * Inspired by UAE MMU patch
7: *
8: * This file is part of the ARAnyM project which builds a new and powerful
9: * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
10: *
11: * ARAnyM is free software; you can redistribute it and/or modify
12: * it under the terms of the GNU General Public License as published by
13: * the Free Software Foundation; either version 2 of the License, or
14: * (at your option) any later version.
15: *
16: * ARAnyM is distributed in the hope that it will be useful,
17: * but WITHOUT ANY WARRANTY; without even the implied warranty of
18: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19: * GNU General Public License for more details.
20: *
21: * You should have received a copy of the GNU General Public License
22: * along with ARAnyM; if not, write to the Free Software
23: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24: */
25:
26: #ifndef CPUMMU_H
27: #define CPUMMU_H
28:
29: #include "compat.h"
1.1.1.3 ! root 30: #include "mmu_common.h"
1.1.1.2 root 31:
32: #ifndef FULLMMU
33: #define FULLMMU
34: #endif
35:
36: #define DUNUSED(x)
37: #define D
38: #if DEBUG
39: #define bug write_log
40: #else
41: #define bug
42: #endif
43:
44: static __inline void flush_internals (void) { }
45:
46: //typedef uae_u8 flagtype;
47:
48: //static m68k_exception except;
49:
50: struct xttrx {
51: uae_u32 log_addr_base : 8;
52: uae_u32 log_addr_mask : 8;
53: uae_u32 enable : 1;
54: uae_u32 s_field : 2;
55: uae_u32 : 3;
56: uae_u32 usr1 : 1;
57: uae_u32 usr0 : 1;
58: uae_u32 : 1;
59: uae_u32 cmode : 2;
60: uae_u32 : 2;
61: uae_u32 write : 1;
62: uae_u32 : 2;
63: };
64:
65: struct mmusr_t {
66: uae_u32 phys_addr : 20;
67: uae_u32 bus_err : 1;
68: uae_u32 global : 1;
69: uae_u32 usr1 : 1;
70: uae_u32 usr0 : 1;
71: uae_u32 super : 1;
72: uae_u32 cmode : 2;
73: uae_u32 modif : 1;
74: uae_u32 : 1;
75: uae_u32 write : 1;
76: uae_u32 ttrhit : 1;
77: uae_u32 resident : 1;
78: };
79:
80: struct log_addr4 {
81: uae_u32 rif : 7;
82: uae_u32 pif : 7;
83: uae_u32 paif : 6;
84: uae_u32 poff : 12;
85: };
86:
87: struct log_addr8 {
88: uae_u32 rif : 7;
89: uae_u32 pif : 7;
90: uae_u32 paif : 5;
91: uae_u32 poff : 13;
92: };
93:
94: #define MMU_TEST_PTEST 1
95: #define MMU_TEST_VERBOSE 2
96: #define MMU_TEST_FORCE_TABLE_SEARCH 4
97: #define MMU_TEST_NO_BUSERR 8
98:
99: extern void mmu_dump_tables(void);
100:
101: #define MMU_TTR_LOGICAL_BASE 0xff000000
102: #define MMU_TTR_LOGICAL_MASK 0x00ff0000
103: #define MMU_TTR_BIT_ENABLED (1 << 15)
104: #define MMU_TTR_BIT_SFIELD_ENABLED (1 << 14)
105: #define MMU_TTR_BIT_SFIELD_SUPER (1 << 13)
106: #define MMU_TTR_SFIELD_SHIFT 13
107: #define MMU_TTR_UX_MASK ((1 << 9) | (1 << 8))
108: #define MMU_TTR_UX_SHIFT 8
109: #define MMU_TTR_CACHE_MASK ((1 << 6) | (1 << 5))
110: #define MMU_TTR_CACHE_SHIFT 5
111: #define MMU_TTR_BIT_WRITE_PROTECT (1 << 2)
112:
113: #define MMU_UDT_MASK 3
114: #define MMU_PDT_MASK 3
115:
116: #define MMU_DES_WP 4
117: #define MMU_DES_USED 8
118:
119: /* page descriptors only */
120: #define MMU_DES_MODIFIED 16
121: #define MMU_DES_SUPER (1 << 7)
122: #define MMU_DES_GLOBAL (1 << 10)
123:
124: #define MMU_ROOT_PTR_ADDR_MASK 0xfffffe00
125: #define MMU_PTR_PAGE_ADDR_MASK_8 0xffffff80
126: #define MMU_PTR_PAGE_ADDR_MASK_4 0xffffff00
127:
128: #define MMU_PAGE_INDIRECT_MASK 0xfffffffc
129: #define MMU_PAGE_ADDR_MASK_8 0xffffe000
130: #define MMU_PAGE_ADDR_MASK_4 0xfffff000
131: #define MMU_PAGE_UR_MASK_8 ((1 << 12) | (1 << 11))
132: #define MMU_PAGE_UR_MASK_4 (1 << 11)
133: #define MMU_PAGE_UR_SHIFT 11
134:
135: #define MMU_MMUSR_ADDR_MASK 0xfffff000
136: #define MMU_MMUSR_B (1 << 11)
137: #define MMU_MMUSR_G (1 << 10)
138: #define MMU_MMUSR_U1 (1 << 9)
139: #define MMU_MMUSR_U0 (1 << 8)
140: #define MMU_MMUSR_Ux (MMU_MMUSR_U1 | MMU_MMUSR_U0)
141: #define MMU_MMUSR_S (1 << 7)
142: #define MMU_MMUSR_CM ((1 << 6) | ( 1 << 5))
143: #define MMU_MMUSR_M (1 << 4)
144: #define MMU_MMUSR_W (1 << 2)
145: #define MMU_MMUSR_T (1 << 1)
146: #define MMU_MMUSR_R (1 << 0)
147:
148: #define TTR_I0 4
149: #define TTR_I1 5
150: #define TTR_D0 6
151: #define TTR_D1 7
152:
153: #define TTR_NO_MATCH 0
154: #define TTR_NO_WRITE 1
155: #define TTR_OK_MATCH 2
156:
157: struct mmu_atc_line {
158: uae_u16 tag;
159: unsigned tt : 1;
160: unsigned valid_data : 1;
161: unsigned valid_inst : 1;
162: unsigned global : 1;
163: unsigned modified : 1;
164: unsigned write_protect : 1;
165: unsigned hw : 1;
166: unsigned bus_fault : 1;
167: uaecptr phys;
168: };
169:
170: /*
171: * We don't need to store the whole logical address in the atc cache, as part of
172: * it is encoded as index into the cache. 14 bits of the address are stored in
173: * the tag, this means at least 6 bits must go into the index. The upper two
174: * bits of the tag define the type of data in the atc line:
175: * - 00: a normal memory address
176: * - 11: invalid memory address or hardware access
177: * (generated via ~ATC_TAG(addr) in the slow path)
178: * - 10: empty atc line
179: */
180:
181: #define ATC_TAG_SHIFT 18
182: #define ATC_TAG(addr) ((uae_u32)(addr) >> ATC_TAG_SHIFT)
183:
184:
185: #define ATC_L1_SIZE_LOG 8
186: #define ATC_L1_SIZE (1 << ATC_L1_SIZE_LOG)
187:
188: #define ATC_L1_INDEX(addr) (((addr) >> 12) % ATC_L1_SIZE)
189:
190: /*
191: * first level atc cache
192: * indexed by [super][data][rw][idx]
193: */
194:
195: typedef struct mmu_atc_line mmu_atc_l1_array[2][2][ATC_L1_SIZE];
196: extern mmu_atc_l1_array atc_l1[2];
197: extern mmu_atc_l1_array *current_atc;
198:
199: #define ATC_L2_SIZE_LOG 12
200: #define ATC_L2_SIZE (1 << ATC_L2_SIZE_LOG)
201:
202: #define ATC_L2_INDEX(addr) ((((addr) >> 12) ^ ((addr) >> (32 - ATC_L2_SIZE_LOG))) % ATC_L2_SIZE)
203:
204: extern struct mmu_atc_line atc_l2[2][ATC_L2_SIZE];
205:
206: /*
207: * lookup address in the level 1 atc cache,
208: * the data and write arguments are constant in the common,
209: * thus allows gcc to generate a constant offset.
210: */
211: static ALWAYS_INLINE bool mmu_lookup(uaecptr addr, bool data, bool write,
212: struct mmu_atc_line **cl)
213: {
214: addr >>= 12;
215: *cl = &(*current_atc)[data ? 1 : 0][write ? 1 : 0][addr % ATC_L1_SIZE];
216: return (*cl)->tag == addr >> (ATC_TAG_SHIFT - 12);
217: }
218:
219: /*
220: * similiar to mmu_user_lookup, but for the use of the moves instruction
221: */
222: static ALWAYS_INLINE bool mmu_user_lookup(uaecptr addr, bool super, bool data,
223: bool write, struct mmu_atc_line **cl)
224: {
225: addr >>= 12;
226: *cl = &atc_l1[super ? 1 : 0][data ? 1 : 0][write ? 1 : 0][addr % ATC_L1_SIZE];
227: return (*cl)->tag == addr >> (ATC_TAG_SHIFT - 12);
228: }
229:
230: extern uae_u16 REGPARAM3 mmu_get_word_unaligned(uaecptr addr, bool data) REGPARAM;
231: extern uae_u32 REGPARAM3 mmu_get_long_unaligned(uaecptr addr, bool data) REGPARAM;
232:
233: extern uae_u8 REGPARAM3 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
234: int size, struct mmu_atc_line *cl) REGPARAM;
235: extern uae_u16 REGPARAM3 mmu_get_word_slow(uaecptr addr, bool super, bool data,
236: int size, struct mmu_atc_line *cl) REGPARAM;
237: extern uae_u32 REGPARAM3 mmu_get_long_slow(uaecptr addr, bool super, bool data,
238: int size, struct mmu_atc_line *cl) REGPARAM;
239:
240: extern void REGPARAM3 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data) REGPARAM;
241: extern void REGPARAM3 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data) REGPARAM;
242:
243: extern void REGPARAM3 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
244: int size, struct mmu_atc_line *cl) REGPARAM;
245: extern void REGPARAM3 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
246: int size, struct mmu_atc_line *cl) REGPARAM;
247: extern void REGPARAM3 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
248: int size, struct mmu_atc_line *cl) REGPARAM;
249:
250: extern void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode);
251:
252: #define FC_DATA (regs.s ? 5 : 1)
253: #define FC_INST (regs.s ? 6 : 2)
254:
255: extern uaecptr REGPARAM3 mmu_translate(uaecptr addr, bool super, bool data, bool write) REGPARAM;
256:
257: extern uae_u32 REGPARAM3 sfc_get_long(uaecptr addr) REGPARAM;
258: extern uae_u16 REGPARAM3 sfc_get_word(uaecptr addr) REGPARAM;
259: extern uae_u8 REGPARAM3 sfc_get_byte(uaecptr addr) REGPARAM;
260: extern void REGPARAM3 dfc_put_long(uaecptr addr, uae_u32 val) REGPARAM;
261: extern void REGPARAM3 dfc_put_word(uaecptr addr, uae_u16 val) REGPARAM;
262: extern void REGPARAM3 dfc_put_byte(uaecptr addr, uae_u8 val) REGPARAM;
263:
264:
265: extern void REGPARAM3 mmu_flush_atc(uaecptr addr, bool super, bool global) REGPARAM;
266: extern void REGPARAM3 mmu_flush_atc_all(bool global) REGPARAM;
267: extern void REGPARAM3 mmu_op_real(uae_u32 opcode, uae_u16 extra) REGPARAM;
268:
269: extern void REGPARAM3 mmu_reset(void) REGPARAM;
270: extern void REGPARAM3 mmu_set_tc(uae_u16 tc) REGPARAM;
271: extern void REGPARAM3 mmu_set_super(bool super) REGPARAM;
272:
273: static ALWAYS_INLINE uaecptr mmu_get_real_address(uaecptr addr, struct mmu_atc_line *cl)
274: {
275: return cl->phys + addr;
276: }
277:
278: static ALWAYS_INLINE uae_u32 mmu_get_long(uaecptr addr, bool data, int size)
279: {
280: struct mmu_atc_line *cl;
281:
282: if (likely(mmu_lookup(addr, data, false, &cl)))
283: return phys_get_long(mmu_get_real_address(addr, cl));
284: return mmu_get_long_slow(addr, regs.s != 0, data, size, cl);
285: }
286:
287: static ALWAYS_INLINE uae_u16 mmu_get_word(uaecptr addr, bool data, int size)
288: {
289: struct mmu_atc_line *cl;
290:
291: if (likely(mmu_lookup(addr, data, false, &cl)))
292: return phys_get_word(mmu_get_real_address(addr, cl));
293: return mmu_get_word_slow(addr, regs.s != 0, data, size, cl);
294: }
295:
296: static ALWAYS_INLINE uae_u8 mmu_get_byte(uaecptr addr, bool data, int size)
297: {
298: struct mmu_atc_line *cl;
299:
300: if (likely(mmu_lookup(addr, data, false, &cl)))
301: return phys_get_byte(mmu_get_real_address(addr, cl));
302: return mmu_get_byte_slow(addr, regs.s != 0, data, size, cl);
303: }
304:
305:
306: static ALWAYS_INLINE void mmu_put_long(uaecptr addr, uae_u32 val, bool data, int size)
307: {
308: struct mmu_atc_line *cl;
309:
310: if (likely(mmu_lookup(addr, data, true, &cl)))
311: phys_put_long(mmu_get_real_address(addr, cl), val);
312: else
313: mmu_put_long_slow(addr, val, regs.s != 0, data, size, cl);
314: }
315:
316: static ALWAYS_INLINE void mmu_put_word(uaecptr addr, uae_u16 val, bool data, int size)
317: {
318: struct mmu_atc_line *cl;
319:
320: if (likely(mmu_lookup(addr, data, true, &cl)))
321: phys_put_word(mmu_get_real_address(addr, cl), val);
322: else
323: mmu_put_word_slow(addr, val, regs.s != 0, data, size, cl);
324: }
325:
326: static ALWAYS_INLINE void mmu_put_byte(uaecptr addr, uae_u8 val, bool data, int size)
327: {
328: struct mmu_atc_line *cl;
329:
330: if (likely(mmu_lookup(addr, data, true, &cl)))
331: phys_put_byte(mmu_get_real_address(addr, cl), val);
332: else
333: mmu_put_byte_slow(addr, val, regs.s != 0, data, size, cl);
334: }
335:
336: static ALWAYS_INLINE uae_u32 mmu_get_user_long(uaecptr addr, bool super, bool data, int size)
337: {
338: struct mmu_atc_line *cl;
339:
340: if (likely(mmu_user_lookup(addr, super, data, false, &cl)))
341: return phys_get_long(mmu_get_real_address(addr, cl));
342: return mmu_get_long_slow(addr, super, data, size, cl);
343: }
344:
345: static ALWAYS_INLINE uae_u16 mmu_get_user_word(uaecptr addr, bool super, bool data, int size)
346: {
347: struct mmu_atc_line *cl;
348:
349: if (likely(mmu_user_lookup(addr, super, data, false, &cl)))
350: return phys_get_word(mmu_get_real_address(addr, cl));
351: return mmu_get_word_slow(addr, super, data, size, cl);
352: }
353:
354: static ALWAYS_INLINE uae_u8 mmu_get_user_byte(uaecptr addr, bool super, bool data, int size)
355: {
356: struct mmu_atc_line *cl;
357:
358: if (likely(mmu_user_lookup(addr, super, data, false, &cl)))
359: return phys_get_byte(mmu_get_real_address(addr, cl));
360: return mmu_get_byte_slow(addr, super, data, size, cl);
361: }
362:
363: static ALWAYS_INLINE void mmu_put_user_long(uaecptr addr, uae_u32 val, bool super, bool data, int size)
364: {
365: struct mmu_atc_line *cl;
366:
367: if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
368: phys_put_long(mmu_get_real_address(addr, cl), val);
369: else
370: mmu_put_long_slow(addr, val, super, data, size, cl);
371: }
372:
373: static ALWAYS_INLINE void mmu_put_user_word(uaecptr addr, uae_u16 val, bool super, bool data, int size)
374: {
375: struct mmu_atc_line *cl;
376:
377: if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
378: phys_put_word(mmu_get_real_address(addr, cl), val);
379: else
380: mmu_put_word_slow(addr, val, super, data, size, cl);
381: }
382:
383: static ALWAYS_INLINE void mmu_put_user_byte(uaecptr addr, uae_u8 val, bool super, bool data, int size)
384: {
385: struct mmu_atc_line *cl;
386:
387: if (likely(mmu_user_lookup(addr, super, data, true, &cl)))
388: phys_put_byte(mmu_get_real_address(addr, cl), val);
389: else
390: mmu_put_byte_slow(addr, val, super, data, size, cl);
391: }
392:
393:
394: static ALWAYS_INLINE void HWput_l(uaecptr addr, uae_u32 l)
395: {
396: put_long (addr, l);
397: }
398: static ALWAYS_INLINE void HWput_w(uaecptr addr, uae_u32 w)
399: {
400: put_word (addr, w);
401: }
402: static ALWAYS_INLINE void HWput_b(uaecptr addr, uae_u32 b)
403: {
404: put_byte (addr, b);
405: }
406: static ALWAYS_INLINE uae_u32 HWget_l(uaecptr addr)
407: {
408: return get_long (addr);
409: }
410: static ALWAYS_INLINE uae_u32 HWget_w(uaecptr addr)
411: {
412: return get_word (addr);
413: }
414: static ALWAYS_INLINE uae_u32 HWget_b(uaecptr addr)
415: {
416: return get_byte (addr);
417: }
418:
419: static ALWAYS_INLINE uae_u32 uae_mmu_get_ilong(uaecptr addr)
420: {
421: if (unlikely(is_unaligned(addr, 4)))
422: return mmu_get_long_unaligned(addr, false);
423: return mmu_get_long(addr, false, sz_long);
424: }
425: static ALWAYS_INLINE uae_u16 uae_mmu_get_iword(uaecptr addr)
426: {
427: if (unlikely(is_unaligned(addr, 2)))
428: return mmu_get_word_unaligned(addr, false);
429: return mmu_get_word(addr, false, sz_word);
430: }
431: static ALWAYS_INLINE uae_u16 uae_mmu_get_ibyte(uaecptr addr)
432: {
433: return mmu_get_byte(addr, false, sz_byte);
434: }
435: static ALWAYS_INLINE uae_u32 uae_mmu_get_long(uaecptr addr)
436: {
437: if (unlikely(is_unaligned(addr, 4)))
438: return mmu_get_long_unaligned(addr, true);
439: return mmu_get_long(addr, true, sz_long);
440: }
441: static ALWAYS_INLINE uae_u16 uae_mmu_get_word(uaecptr addr)
442: {
443: if (unlikely(is_unaligned(addr, 2)))
444: return mmu_get_word_unaligned(addr, true);
445: return mmu_get_word(addr, true, sz_word);
446: }
447: static ALWAYS_INLINE uae_u8 uae_mmu_get_byte(uaecptr addr)
448: {
449: return mmu_get_byte(addr, true, sz_byte);
450: }
451: static ALWAYS_INLINE void uae_mmu_put_long(uaecptr addr, uae_u32 val)
452: {
453: if (unlikely(is_unaligned(addr, 4)))
454: mmu_put_long_unaligned(addr, val, true);
455: else
456: mmu_put_long(addr, val, true, sz_long);
457: }
458: static ALWAYS_INLINE void uae_mmu_put_word(uaecptr addr, uae_u16 val)
459: {
460: if (unlikely(is_unaligned(addr, 2)))
461: mmu_put_word_unaligned(addr, val, true);
462: else
463: mmu_put_word(addr, val, true, sz_word);
464: }
465: static ALWAYS_INLINE void uae_mmu_put_byte(uaecptr addr, uae_u8 val)
466: {
467: mmu_put_byte(addr, val, true, sz_byte);
468: }
469:
470: STATIC_INLINE void put_byte_mmu (uaecptr addr, uae_u32 v)
471: {
472: uae_mmu_put_byte (addr, v);
473: }
474: STATIC_INLINE void put_word_mmu (uaecptr addr, uae_u32 v)
475: {
476: uae_mmu_put_word (addr, v);
477: }
478: STATIC_INLINE void put_long_mmu (uaecptr addr, uae_u32 v)
479: {
480: uae_mmu_put_long (addr, v);
481: }
482: STATIC_INLINE uae_u32 get_byte_mmu (uaecptr addr)
483: {
484: return uae_mmu_get_byte (addr);
485: }
486: STATIC_INLINE uae_u32 get_word_mmu (uaecptr addr)
487: {
488: return uae_mmu_get_word (addr);
489: }
490: STATIC_INLINE uae_u32 get_long_mmu (uaecptr addr)
491: {
492: return uae_mmu_get_long (addr);
493: }
494: STATIC_INLINE uae_u32 get_ibyte_mmu (int o)
495: {
496: uae_u32 pc = m68k_getpc () + o;
497: return uae_mmu_get_iword (pc);
498: }
499: STATIC_INLINE uae_u32 get_iword_mmu (int o)
500: {
501: uae_u32 pc = m68k_getpc () + o;
502: return uae_mmu_get_iword (pc);
503: }
504: STATIC_INLINE uae_u32 get_ilong_mmu (int o)
505: {
506: uae_u32 pc = m68k_getpc () + o;
507: return uae_mmu_get_ilong (pc);
508: }
509: STATIC_INLINE uae_u32 next_iword_mmu (void)
510: {
511: uae_u32 pc = m68k_getpc ();
512: m68k_incpci (2);
513: return uae_mmu_get_iword (pc);
514: }
515: STATIC_INLINE uae_u32 next_ilong_mmu (void)
516: {
517: uae_u32 pc = m68k_getpc ();
518: m68k_incpci (4);
519: return uae_mmu_get_ilong (pc);
520: }
521:
522: extern void m68k_do_rts_mmu (void);
523: extern void m68k_do_rte_mmu (uaecptr a7);
524: extern void m68k_do_bsr_mmu (uaecptr oldpc, uae_s32 offset);
525:
526: #endif /* CPUMMU_H */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.