|
|
1.1 root 1: /*
2: * cpummu.cpp - 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: #define DEBUG 0
27: #define USETAG 0
28:
29: #include "sysconfig.h"
30: #include "sysdeps.h"
31:
32: #include "options_cpu.h"
33: #include "memory.h"
34: #include "newcpu.h"
35: //#include "debug.h"
36: #include "main.h"
37: #include "cpummu.h"
38:
39: #define DBG_MMU_VERBOSE 1
40: #define DBG_MMU_SANITY 1
41: #define write_log printf
42:
43: #ifdef FULLMMU
44:
45: mmu_atc_l1_array atc_l1[2];
46: mmu_atc_l1_array *current_atc;
47: struct mmu_atc_line atc_l2[2][ATC_L2_SIZE];
48:
49: # ifdef ATC_STATS
50: static unsigned int mmu_atc_hits[ATC_L2_SIZE];
51: # endif
52:
53:
54: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
55: {
56: DUNUSED(label);
57: uae_u32 from_addr, to_addr;
58:
59: from_addr = ttr & MMU_TTR_LOGICAL_BASE;
60: to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8;
61:
62:
63: fprintf(stderr, "%s: [%08lx] %08lx - %08lx enabled=%d supervisor=%d wp=%d cm=%02d\n",
64: label, ttr,
65: from_addr, to_addr,
66: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0,
67: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT,
68: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0,
69: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT
70: );
71: }
72:
73: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
74: {
75: uae_u32 * ttr;
76: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0;
77: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1;
78:
79: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0)
80: ttr = ttr1;
81: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0)
82: ttr = ttr0;
83: else
84: return;
85:
86: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE;
87: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8;
88: *ttr |= MMU_TTR_BIT_ENABLED;
89:
90: fprintf(stderr, "MMU: map transparent mapping of %08x\n", *ttr);
91: }
92:
93: /* check if an address matches a ttr */
94: static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
95: {
96: if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */
97: uae_u8 msb, mask;
98:
99: msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
100: mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
101:
102: if (!(msb & ~mask)) {
103:
104: if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
105: if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
106: return TTR_NO_MATCH;
107: }
108: }
109:
110: return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
111: }
112: }
113: return TTR_NO_MATCH;
114: }
115:
116: static inline int mmu_match_ttr(uaecptr addr, bool super, bool data)
117: {
118: int res;
119:
120: if (data) {
121: res = mmu_do_match_ttr(regs.dtt0, addr, super);
122: if (res == TTR_NO_MATCH)
123: res = mmu_do_match_ttr(regs.dtt1, addr, super);
124: } else {
125: res = mmu_do_match_ttr(regs.itt0, addr, super);
126: if (res == TTR_NO_MATCH)
127: res = mmu_do_match_ttr(regs.itt1, addr, super);
128: }
129: return res;
130: }
131:
132: #if DEBUG
133: /* {{{ mmu_dump_table */
134: static void mmu_dump_table(const char * label, uaecptr root_ptr)
135: {
136: DUNUSED(label);
137: const int ROOT_TABLE_SIZE = 128,
138: PTR_TABLE_SIZE = 128,
139: PAGE_TABLE_SIZE = 64,
140: ROOT_INDEX_SHIFT = 25,
141: PTR_INDEX_SHIFT = 18;
142: // const int PAGE_INDEX_SHIFT = 12;
143: int root_idx, ptr_idx, page_idx;
144: uae_u32 root_des, ptr_des, page_des;
145: uaecptr ptr_des_addr, page_addr,
146: root_log, ptr_log, page_log;
147:
148: fprintf(stderr, "%s: root=%lx\n", label, root_ptr);
149:
150: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
151: root_des = phys_get_long(root_ptr + root_idx);
152:
153: if ((root_des & 2) == 0)
154: continue; /* invalid */
155:
156: fprintf(stderr, "ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx,
157: root_des & 8 ? 1 : 0,
158: root_des & 4 ? 1 : 0,
159: root_des & 3
160: );
161:
162: root_log = root_idx << ROOT_INDEX_SHIFT;
163:
164: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK;
165:
166: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) {
167: struct {
168: uaecptr log, phys;
169: int start_idx, n_pages; /* number of pages covered by this entry */
170: uae_u32 match;
171: } page_info[PAGE_TABLE_SIZE];
172: int n_pages_used;
173:
174: ptr_des = phys_get_long(ptr_des_addr + ptr_idx);
175: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT);
176:
177: if ((ptr_des & 2) == 0)
178: continue; /* invalid */
179:
180: page_addr = ptr_des & (regs.mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4);
181:
182: n_pages_used = -1;
183: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) {
184:
185: page_des = phys_get_long(page_addr + page_idx);
186: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT
187:
188: switch (page_des & 3) {
189: case 0: /* invalid */
190: continue;
191: case 1: case 3: /* resident */
192: case 2: /* indirect */
193: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) {
194: /* use the next entry */
195: n_pages_used++;
196:
197: page_info[n_pages_used].match = page_des;
198: page_info[n_pages_used].n_pages = 1;
199: page_info[n_pages_used].start_idx = page_idx;
200: page_info[n_pages_used].log = page_log;
201: } else {
202: page_info[n_pages_used].n_pages++;
203: }
204: break;
205: }
206: }
207:
208: if (n_pages_used == -1)
209: continue;
210:
211: fprintf(stderr, " PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx,
212: ptr_des & 8 ? 1 : 0,
213: ptr_des & 4 ? 1 : 0,
214: ptr_des & 3
215: );
216:
217:
218: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) {
219: page_des = page_info[page_idx].match;
220:
221: if ((page_des & MMU_PDT_MASK) == 2) {
222: fprintf(stderr, " PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n",
223: page_info[page_idx].start_idx,
224: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
225: page_info[page_idx].log,
226: page_des & MMU_PAGE_INDIRECT_MASK
227: );
228:
229: } else {
230: fprintf(stderr, " PAGE: %03d-%03d log=%08lx addr=%08lx UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d\n",
231: page_info[page_idx].start_idx,
232: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
233: page_info[page_idx].log,
234: page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4),
235: (page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT,
236: page_des & MMU_DES_GLOBAL ? 1 : 0,
237: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT,
238: page_des & MMU_DES_SUPER ? 1 : 0,
239: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT,
240: page_des & MMU_DES_MODIFIED ? 1 : 0,
241: page_des & MMU_DES_USED ? 1 : 0,
242: page_des & MMU_DES_WP ? 1 : 0
243: );
244: }
245: }
246: }
247:
248: }
249: }
250: /* }}} */
251: #endif
252:
253: /* {{{ mmu_dump_atc */
254: void mmu_dump_atc(void)
255: {
256: int i, j;
257: for (i = 0; i < 2; i++) {
258: for (j = 0; j < ATC_L2_SIZE; j++) {
259: if (atc_l2[i][j].tag == 0x8000)
260: continue;
261: fprintf(stderr, "ATC[%02d] G=%d TT=%d M=%d WP=%d VD=%d VI=%d tag=%08x --> phys=%08x\n",
262: j, atc_l2[i][j].global, atc_l2[i][j].tt, atc_l2[i][j].modified,
263: atc_l2[i][j].write_protect, atc_l2[i][j].valid_data, atc_l2[i][j].valid_inst,
264: atc_l2[i][j].tag, atc_l2[i][j].phys);
265: }
266: }
267: }
268: /* }}} */
269:
270: /* {{{ mmu_dump_tables */
271: void mmu_dump_tables(void)
272: {
273: fprintf(stderr, "URP: %08x SRP: %08x MMUSR: %x TC: %x\n", regs.urp, regs.srp, regs.mmusr, regs.tcr);
274: mmu_dump_ttr(L"DTT0", regs.dtt0);
275: mmu_dump_ttr(L"DTT1", regs.dtt1);
276: mmu_dump_ttr(L"ITT0", regs.itt0);
277: mmu_dump_ttr(L"ITT1", regs.itt1);
278: mmu_dump_atc();
279: #if DEBUG
280: mmu_dump_table("SRP", regs.srp);
281: #endif
282: }
283: /* }}} */
284:
285: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write);
286:
287: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
288: {
289: return (super ? 4 : 0) | (data ? 1 : 2);
290: }
291:
292: static void mmu_bus_error(uaecptr addr, int fc, bool write, int size)
293: {
294: uae_u16 ssw = 0;
295:
296: ssw |= fc & MMU_SSW_TM; /* Copy TM */
297: switch (size) {
298: case sz_byte:
299: ssw |= MMU_SSW_SIZE_B;
300: break;
301: case sz_word:
302: ssw |= MMU_SSW_SIZE_W;
303: break;
304: case sz_long:
305: ssw |= MMU_SSW_SIZE_L;
306: break;
307: }
308:
309: regs.wb3_status = write ? 0x80 | ssw : 0;
310: if (!write)
311: ssw |= MMU_SSW_RW;
312:
313: regs.mmu_fault_addr = addr;
314: regs.mmu_ssw = ssw | MMU_SSW_ATC;
315:
316: fprintf(stderr, "BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc());
317:
318: //write_log(L"BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc());
319:
320: except=2;
321: }
322:
323: /*
324: * Update the atc line for a given address by doing a mmu lookup.
325: */
326: static uaecptr mmu_fill_atc_l2(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l)
327: {
328: int res;
329: uae_u32 desc;
330:
331: l->tag = ATC_TAG(addr);
332: l->hw = l->bus_fault = 0;
333:
334: /* check ttr0 */
335: res = mmu_match_ttr(addr, super, data);
336: if (res != TTR_NO_MATCH) {
337: l->tt = 1;
338: if (data) {
339: l->valid_data = 1;
340: l->valid_inst = mmu_match_ttr(addr, super, 0) == res;
341: } else {
342: l->valid_inst = 1;
343: l->valid_data = mmu_match_ttr(addr, super, 1) == res;
344: }
345: l->global = 1;
346: l->modified = 1;
347: l->write_protect = (res == TTR_NO_WRITE);
348: l->phys = 0;
349:
350: return 0;
351: }
352:
353: l->tt = 0;
354: if (!regs.mmu_enabled) {
355: l->valid_data = l->valid_inst = 1;
356: l->global = 1;
357: l->modified = 1;
358: l->write_protect = 0;
359: l->phys = 0;
360: return 0;
361: }
362:
363: SAVE_EXCEPTION;
364: // TRY(prb) {
365: except = 0;
366: desc = mmu_lookup_pagetable(addr, super, write);
367: #if DEBUG > 2
368: fprintf(stderr, "translate: %x,%u,%u,%u -> %x\n", addr, super, write, data, desc);
369: #endif
370: RESTORE_EXCEPTION;
371: CATCH(prb) {
372: RESTORE_EXCEPTION;
373: /* bus error during table search */
374: desc = 0;
375: goto fail;
376: }
377:
378: if ((desc & 1) == 0 || (!super && desc & MMU_MMUSR_S)) {
379: fail:
380: l->valid_data = l->valid_inst = 0;
381: l->global = 0;
382: } else {
383: l->valid_data = l->valid_inst = 1;
384: if (regs.mmu_pagesize_8k)
385: l->phys = (desc & ~0x1fff) - (addr & ~0x1fff);
386: else
387: l->phys = (desc & ~0xfff) - (addr & ~0xfff);
388: l->global = (desc & MMU_MMUSR_G) != 0;
389: l->modified = (desc & MMU_MMUSR_M) != 0;
390: l->write_protect = (desc & MMU_MMUSR_W) != 0;
391: }
392:
393: return desc;
394: }
395:
396: static ALWAYS_INLINE bool mmu_fill_atc_l1(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1)
397: {
398: int idx = ATC_L2_INDEX(addr);
399: int tag = ATC_TAG(addr);
400: struct mmu_atc_line *l = &atc_l2[super ? 1 : 0][idx];
401:
402: if (l->tag != tag) {
403: restart:
404: mmu_fill_atc_l2(addr, super, data, write, l);
405: }
406: if (!(data ? l->valid_data : l->valid_inst)) {
407: fprintf(stderr, "MMU: non-resident page (%x,%x,%x)!\n", addr, regs.pc, regs.fault_pc);
408: goto fail;
409: }
410: if (write) {
411: if (l->write_protect) {
412: fprintf(stderr, "MMU: write protected (via %s) %lx\n", l->tt ? "ttr" : "atc", addr);
413: goto fail;
414: }
415: if (!l->modified)
416: goto restart;
417: }
418: *l1 = *l;
419: #if 0
420: uaecptr phys_addr = addr + l1->phys;
421: if ((phys_addr & 0xfff00000) == 0x00f00000) {
422: l1->hw = 1;
423: goto fail;
424: }
425: if ((phys_addr & 0xfff00000) == 0xfff00000) {
426: l1->hw = 1;
427: l1->phys -= 0xff000000;
428: goto fail;
429: }
430:
431: if (!test_ram_boundary(phys_addr, 1, super, write)) {
432: l1->bus_fault = 1;
433: goto fail;
434: }
435: #endif
436: return true;
437:
438: fail:
439: l1->tag = ~l1->tag;
440: return false;
441: }
442:
443: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write)
444: {
445: struct mmu_atc_line *l;
446:
447: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)];
448: mmu_fill_atc_l2(addr, super, data, write, l);
449: if (!(data ? l->valid_data : l->valid_inst))
450: except=2;
451:
452: return addr + l->phys;
453: }
454:
455: /*
456: * Lookup the address by walking the page table and updating
457: * the page descriptors accordingly. Returns the found descriptor
458: * or produces a bus error.
459: */
460: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write)
461: {
462: uae_u32 desc, desc_addr, wp;
463: int i;
464:
465: wp = 0;
466: desc = super ? regs.srp : regs.urp;
467:
468: /* fetch root table descriptor */
469: i = (addr >> 23) & 0x1fc;
470: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
471: desc = phys_get_long(desc_addr);
472: if ((desc & 2) == 0) {
473: fprintf(stderr, "MMU: invalid root descriptor for %lx\n", addr);
474: return 0;
475: }
476:
477: wp |= desc;
478: if ((desc & MMU_DES_USED) == 0)
479: phys_put_long(desc_addr, desc | MMU_DES_USED);
480:
481: /* fetch pointer table descriptor */
482: i = (addr >> 16) & 0x1fc;
483: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
484: desc = phys_get_long(desc_addr);
485: if ((desc & 2) == 0) {
486: fprintf(stderr, "MMU: invalid ptr descriptor for %lx\n", addr);
487: return 0;
488: }
489: wp |= desc;
490: if ((desc & MMU_DES_USED) == 0)
491: phys_put_long(desc_addr, desc | MMU_DES_USED);
492:
493: /* fetch page table descriptor */
494: if (regs.mmu_pagesize_8k) {
495: i = (addr >> 11) & 0x7c;
496: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) | i;
497: } else {
498: i = (addr >> 10) & 0xfc;
499: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) | i;
500: }
501:
502: desc = phys_get_long(desc_addr);
503: if ((desc & 3) == 2) {
504: /* indirect */
505: desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
506: desc = phys_get_long(desc_addr);
507: }
508: if ((desc & 1) == 0) {
509: fprintf(stderr, "MMU: invalid page descriptor log=%08lx desc=%08lx @%08lx\n", addr, desc, desc_addr);
510: return desc;
511: }
512:
513: desc |= wp & MMU_DES_WP;
514: if (write) {
515: if (desc & MMU_DES_WP) {
516: if ((desc & MMU_DES_USED) == 0) {
517: desc |= MMU_DES_USED;
518: phys_put_long(desc_addr, desc);
519: }
520: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
521: (MMU_DES_USED|MMU_DES_MODIFIED)) {
522: desc |= MMU_DES_USED|MMU_DES_MODIFIED;
523: phys_put_long(desc_addr, desc);
524: }
525: } else {
526: if ((desc & MMU_DES_USED) == 0) {
527: desc |= MMU_DES_USED;
528: phys_put_long(desc_addr, desc);
529: }
530: }
531: return desc;
532: }
533:
534: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data)
535: {
536: uae_u16 res;
537:
538: res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8;
539: SAVE_EXCEPTION;
540:
541: // TRY(prb) {
542: except = 0;
543: res |= mmu_get_byte(addr + 1, data, sz_word);
544: RESTORE_EXCEPTION;
545:
546: CATCH(prb) {
547: RESTORE_EXCEPTION;
548: regs.mmu_fault_addr = addr;
549: regs.mmu_ssw |= MMU_SSW_MA;
550: except=2;
551: }
552: return res;
553: }
554:
555: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data)
556: {
557: uae_u32 res;
558:
559: if (likely(!(addr & 1))) {
560: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16;
561: SAVE_EXCEPTION;
562: // TRY(prb) {
563: except = 0;
564: res |= mmu_get_word(addr + 2, data, sz_long);
565: RESTORE_EXCEPTION;
566: CATCH(prb) {
567: RESTORE_EXCEPTION;
568: regs.mmu_fault_addr = addr;
569: regs.mmu_ssw |= MMU_SSW_MA;
570: except=2;
571: }
572: } else {
573: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8;
574: SAVE_EXCEPTION;
575: // TRY(prb) {
576: except = 0;
577: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8;
578: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8;
579: res |= mmu_get_byte(addr + 3, data, sz_long);
580: RESTORE_EXCEPTION;
581:
582: CATCH(prb) {
583: RESTORE_EXCEPTION;
584: regs.mmu_fault_addr = addr;
585: regs.mmu_ssw |= MMU_SSW_MA;
586: except=2;
587: }
588: }
589: return res;
590: }
591:
592: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
593: int size, struct mmu_atc_line *cl)
594: {
595: uae_u32 tag = ATC_TAG(addr);
596:
597: if (USETAG && cl->tag == (uae_u16)~tag) {
598: redo:
599: if (cl->hw)
600: return HWget_b(cl->phys + addr);
601: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
602: return 0;
603: }
604:
605: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
606: goto redo;
607:
608: return phys_get_byte(mmu_get_real_address(addr, cl));
609: }
610:
611: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
612: int size, struct mmu_atc_line *cl)
613: {
614: uae_u32 tag = ATC_TAG(addr);
615:
616: if (USETAG && cl->tag == (uae_u16)~tag) {
617: redo:
618: if (cl->hw)
619: return HWget_w(cl->phys + addr);
620: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
621: return 0;
622: }
623:
624: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
625: goto redo;
626:
627: return phys_get_word(mmu_get_real_address(addr, cl));
628: }
629:
630: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
631: int size, struct mmu_atc_line *cl)
632: {
633: uae_u32 tag = ATC_TAG(addr);
634:
635: if (USETAG && cl->tag == (uae_u16)~tag) {
636: redo:
637: if (cl->hw)
638: return HWget_l(cl->phys + addr);
639: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
640: return 0;
641: }
642:
643: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
644: goto redo;
645:
646: return phys_get_long(mmu_get_real_address(addr, cl));
647: }
648:
649: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data)
650: {
651: SAVE_EXCEPTION;
652: // TRY(prb) {
653: except = 0;
654: if (likely(!(addr & 1))) {
655: mmu_put_word(addr, val >> 16, data, sz_long);
656: mmu_put_word(addr + 2, val, data, sz_long);
657: } else {
658: mmu_put_byte(addr, val >> 24, data, sz_long);
659: mmu_put_byte(addr + 1, val >> 16, data, sz_long);
660: mmu_put_byte(addr + 2, val >> 8, data, sz_long);
661: mmu_put_byte(addr + 3, val, data, sz_long);
662: }
663: RESTORE_EXCEPTION;
664:
665: CATCH(prb) {
666: RESTORE_EXCEPTION;
667: regs.wb3_data = val;
668: if (regs.mmu_fault_addr != addr) {
669: regs.mmu_fault_addr = addr;
670: regs.mmu_ssw |= MMU_SSW_MA;
671: }
672: except=2;
673: }
674: }
675:
676: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data)
677: {
678: SAVE_EXCEPTION;
679: // TRY(prb) {
680: except = 0;
681: mmu_put_byte(addr, val >> 8, data, sz_word);
682: mmu_put_byte(addr + 1, val, data, sz_word);
683: RESTORE_EXCEPTION;
684:
685: CATCH(prb) {
686: RESTORE_EXCEPTION;
687: regs.wb3_data = val;
688: if (regs.mmu_fault_addr != addr) {
689: regs.mmu_fault_addr = addr;
690: regs.mmu_ssw |= MMU_SSW_MA;
691: }
692: except=2;
693: }
694: }
695:
696: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
697: int size, struct mmu_atc_line *cl)
698: {
699: uae_u32 tag = ATC_TAG(addr);
700:
701: if (USETAG && cl->tag == (uae_u16)~tag) {
702: redo:
703: if (cl->hw) {
704: HWput_b(cl->phys + addr, val);
705: return;
706: }
707: regs.wb3_data = val;
708: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
709: return;
710: }
711:
712: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
713: goto redo;
714:
715: phys_put_byte(mmu_get_real_address(addr, cl), val);
716: }
717:
718: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
719: int size, struct mmu_atc_line *cl)
720: {
721: uae_u32 tag = ATC_TAG(addr);
722:
723: if (USETAG && cl->tag == (uae_u16)~tag) {
724: redo:
725: if (cl->hw) {
726: HWput_w(cl->phys + addr, val);
727: return;
728: }
729: regs.wb3_data = val;
730: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
731: return;
732: }
733:
734: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
735: goto redo;
736:
737: phys_put_word(mmu_get_real_address(addr, cl), val);
738: }
739:
740: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
741: int size, struct mmu_atc_line *cl)
742: {
743: uae_u32 tag = ATC_TAG(addr);
744:
745: if (USETAG && cl->tag == (uae_u16)~tag) {
746: redo:
747: if (cl->hw) {
748: HWput_l(cl->phys + addr, val);
749: return;
750: }
751: regs.wb3_data = val;
752: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
753: return;
754: }
755:
756: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
757: goto redo;
758:
759: phys_put_long(mmu_get_real_address(addr, cl), val);
760: }
761:
762: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
763: {
764: bool super = (regs.sfc & 4) != 0;
765: bool data = (regs.sfc & 3) != 2;
766: uae_u32 res;
767:
768: if (likely(!is_unaligned(addr, 4)))
769: return mmu_get_user_long(addr, super, data, sz_long);
770:
771: if (likely(!(addr & 1))) {
772: res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16;
773: SAVE_EXCEPTION;
774: // TRY(prb) {
775: except = 0;
776: res |= mmu_get_user_word(addr + 2, super, data, sz_long);
777: RESTORE_EXCEPTION;
778:
779: CATCH(prb) {
780: RESTORE_EXCEPTION;
781: regs.mmu_fault_addr = addr;
782: regs.mmu_ssw |= MMU_SSW_MA;
783: except=2;
784: }
785: } else {
786: res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8;
787: SAVE_EXCEPTION;
788: // TRY(prb) {
789: except = 0;
790: res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8;
791: res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8;
792: res |= mmu_get_user_byte(addr + 3, super, data, sz_long);
793: RESTORE_EXCEPTION;
794:
795: CATCH(prb) {
796: RESTORE_EXCEPTION;
797: regs.mmu_fault_addr = addr;
798: regs.mmu_ssw |= MMU_SSW_MA;
799: except=2;
800: }
801: }
802: return res;
803: }
804:
805: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
806: {
807: bool super = (regs.sfc & 4) != 0;
808: bool data = (regs.sfc & 3) != 2;
809: uae_u16 res;
810:
811: if (likely(!is_unaligned(addr, 2)))
812: return mmu_get_user_word(addr, super, data, sz_word);
813:
814: res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8;
815: SAVE_EXCEPTION;
816: // TRY(prb) {
817: except = 0;
818: res |= mmu_get_user_byte(addr + 1, super, data, sz_word);
819: RESTORE_EXCEPTION;
820:
821: CATCH(prb) {
822: RESTORE_EXCEPTION;
823: regs.mmu_fault_addr = addr;
824: regs.mmu_ssw |= MMU_SSW_MA;
825: except=2;
826: }
827: return res;
828: }
829:
830: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
831: {
832: bool super = (regs.sfc & 4) != 0;
833: bool data = (regs.sfc & 3) != 2;
834:
835: return mmu_get_user_byte(addr, super, data, sz_byte);
836: }
837:
838: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
839: {
840: bool super = (regs.dfc & 4) != 0;
841: bool data = (regs.dfc & 3) != 2;
842:
843: SAVE_EXCEPTION;
844: // TRY(prb) {
845: except = 0;
846: if (likely(!is_unaligned(addr, 4)))
847: mmu_put_user_long(addr, val, super, data, sz_long);
848: else if (likely(!(addr & 1))) {
849: mmu_put_user_word(addr, val >> 16, super, data, sz_long);
850: mmu_put_user_word(addr + 2, val, super, data, sz_long);
851: } else {
852: mmu_put_user_byte(addr, val >> 24, super, data, sz_long);
853: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long);
854: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long);
855: mmu_put_user_byte(addr + 3, val, super, data, sz_long);
856: }
857: RESTORE_EXCEPTION;
858:
859: CATCH(prb) {
860: RESTORE_EXCEPTION;
861: regs.wb3_data = val;
862: if (regs.mmu_fault_addr != addr) {
863: regs.mmu_fault_addr = addr;
864: regs.mmu_ssw |= MMU_SSW_MA;
865: }
866: except=2;
867: }
868: }
869:
870: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
871: {
872: bool super = (regs.dfc & 4) != 0;
873: bool data = (regs.dfc & 3) != 2;
874:
875: SAVE_EXCEPTION;
876: // TRY(prb) {
877: except = 0;
878: if (likely(!is_unaligned(addr, 2)))
879: mmu_put_user_word(addr, val, super, data, sz_word);
880: else {
881: mmu_put_user_byte(addr, val >> 8, super, data, sz_word);
882: mmu_put_user_byte(addr + 1, val, super, data, sz_word);
883: }
884: RESTORE_EXCEPTION;
885:
886: CATCH(prb) {
887: RESTORE_EXCEPTION;
888: regs.wb3_data = val;
889: if (regs.mmu_fault_addr != addr) {
890: regs.mmu_fault_addr = addr;
891: regs.mmu_ssw |= MMU_SSW_MA;
892: }
893: except=2;
894: }
895: }
896:
897: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
898: {
899: bool super = (regs.dfc & 4) != 0;
900: bool data = (regs.dfc & 3) != 2;
901:
902: SAVE_EXCEPTION;
903: // TRY(prb) {
904: except = 0;
905: mmu_put_user_byte(addr, val, super, data, sz_byte);
906: RESTORE_EXCEPTION;
907:
908: CATCH(prb) {
909: RESTORE_EXCEPTION;
910: regs.wb3_data = val;
911: except=2;
912: }
913: }
914:
915: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
916: {
917: bool super = (regs.dfc & 4) != 0;
918: DUNUSED(extra);
919: if ((opcode & 0xFE0) == 0x0500) {
920: bool glob;
921: int regno;
922: //D(didflush = 0);
923: uae_u32 addr;
924: /* PFLUSH */
925: regno = opcode & 7;
926: glob = (opcode & 8) != 0;
927:
928: if (opcode & 16) {
929: fprintf(stderr, "pflusha(%u,%u)\n", glob, regs.dfc);
930: mmu_flush_atc_all(glob);
931: } else {
932: addr = m68k_areg(regs, regno);
933: fprintf(stderr, "pflush(%u,%u,%x)\n", glob, regs.dfc, addr);
934: mmu_flush_atc(addr, super, glob);
935: }
936: flush_internals();
937: #ifdef USE_JIT
938: flush_icache(0);
939: #endif
940: } else if ((opcode & 0x0FD8) == 0x548) {
941: bool write;
942: int regno;
943: uae_u32 addr;
944:
945: regno = opcode & 7;
946: write = (opcode & 32) == 0;
947: addr = m68k_areg(regs, regno);
948: fprintf(stderr, "PTEST%c (A%d) %08x DFC=%d\n", write ? 'W' : 'R', regno, addr, regs.dfc);
949: mmu_flush_atc(addr, super, true);
950: SAVE_EXCEPTION;
951: // TRY(prb) {
952: except = 0;
953: struct mmu_atc_line *l;
954: uae_u32 desc;
955: bool data = (regs.dfc & 3) != 2;
956:
957: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)];
958: desc = mmu_fill_atc_l2(addr, super, data, write, l);
959: if (!(data ? l->valid_data : l->valid_inst))
960: regs.mmusr = MMU_MMUSR_B;
961: else if (l->tt)
962: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
963: else {
964: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|
965: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W);
966: regs.mmusr |= MMU_MMUSR_R;
967: }
968:
969: CATCH(prb) {
970: regs.mmusr = MMU_MMUSR_B;
971: }
972: RESTORE_EXCEPTION;
973: fprintf(stderr, "PTEST result: mmusr %08x\n", regs.mmusr);
974: } else
975: op_illg (opcode);
976: }
977:
978: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
979: {
980: struct mmu_atc_line *l;
981: int i, j;
982:
983: l = atc_l1[super ? 1 : 0][0][0];
984: i = ATC_L1_INDEX(addr);
985: for (j = 0; j < 4; j++) {
986: if (global || !l[i].global)
987: l[i].tag = 0x8000;
988: l += ATC_L1_SIZE;
989: }
990: if (regs.mmu_pagesize_8k) {
991: i = ATC_L1_INDEX(addr) ^ 1;
992: for (j = 0; j < 4; j++) {
993: if (global || !l[i].global)
994: l[i].tag = 0x8000;
995: l += ATC_L1_SIZE;
996: }
997: }
998: l = atc_l2[super ? 1 : 0];
999: i = ATC_L2_INDEX(addr);
1000: if (global || !l[i].global)
1001: l[i].tag = 0x8000;
1002: if (regs.mmu_pagesize_8k) {
1003: i ^= 1;
1004: if (global || !l[i].global)
1005: l[i].tag = 0x8000;
1006: }
1007: }
1008:
1009: void REGPARAM2 mmu_flush_atc_all(bool global)
1010: {
1011: struct mmu_atc_line *l;
1012: unsigned int i;
1013:
1014: l = atc_l1[0][0][0];
1015: for (i = 0; i < sizeof(atc_l1) / sizeof(*l); l++, i++) {
1016: if (global || !l->global)
1017: l->tag = 0x8000;
1018: }
1019:
1020: l = atc_l2[0];
1021: for (i = 0; i < sizeof(atc_l2) / sizeof(*l); l++, i++) {
1022: if (global || !l->global)
1023: l->tag = 0x8000;
1024: }
1025: }
1026:
1027: void REGPARAM2 mmu_reset(void)
1028: {
1029: mmu_flush_atc_all(true);
1030: #if 0
1031: regs.urp = regs.srp = 0;
1032: regs.itt0 = regs.itt0 = 0;
1033: regs.dtt0 = regs.dtt0 = 0;
1034: regs.mmusr = 0;
1035: #endif
1036: }
1037:
1038:
1039: void REGPARAM2 mmu_set_tc(uae_u16 tc)
1040: {
1041: #if 0
1042: if (regs.tcr == tc)
1043: return;
1044: regs.tcr = tc;
1045: #endif
1046: regs.mmu_enabled = tc & 0x8000 ? 1 : 0;
1047: regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0;
1048: mmu_flush_atc_all(true);
1049:
1050: write_log("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k);
1051: }
1052:
1053: void REGPARAM2 mmu_set_super(bool super)
1054: {
1055: current_atc = &atc_l1[super ? 1 : 0];
1056: }
1057:
1058: #else
1059:
1060: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
1061: {
1062: if ((opcode & 0xFE0) == 0x0500) {
1063: /* PFLUSH instruction */
1064: flush_internals();
1065: } else if ((opcode & 0x0FD8) == 0x548) {
1066: /* PTEST instruction */
1067: } else
1068: op_illg(opcode);
1069: }
1070:
1071: #endif
1072:
1073: /*
1074: vim:ts=4:sw=4:
1075: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.