|
|
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());
1.1.1.2 ! root 319: //activate_debugger();
1.1 root 320:
1.1.1.2 ! root 321: // THROW(2); /* Removed by Laurent */
1.1 root 322: except=2;
323: }
324:
325: /*
326: * Update the atc line for a given address by doing a mmu lookup.
327: */
328: static uaecptr mmu_fill_atc_l2(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l)
329: {
330: int res;
331: uae_u32 desc;
332:
333: l->tag = ATC_TAG(addr);
334: l->hw = l->bus_fault = 0;
335:
336: /* check ttr0 */
337: res = mmu_match_ttr(addr, super, data);
338: if (res != TTR_NO_MATCH) {
339: l->tt = 1;
340: if (data) {
341: l->valid_data = 1;
342: l->valid_inst = mmu_match_ttr(addr, super, 0) == res;
343: } else {
344: l->valid_inst = 1;
345: l->valid_data = mmu_match_ttr(addr, super, 1) == res;
346: }
347: l->global = 1;
348: l->modified = 1;
349: l->write_protect = (res == TTR_NO_WRITE);
350: l->phys = 0;
351:
352: return 0;
353: }
354:
355: l->tt = 0;
356: if (!regs.mmu_enabled) {
357: l->valid_data = l->valid_inst = 1;
358: l->global = 1;
359: l->modified = 1;
360: l->write_protect = 0;
361: l->phys = 0;
362: return 0;
363: }
364:
365: SAVE_EXCEPTION;
1.1.1.2 ! root 366: // TRY(prb) { /* Removed by Laurent */
! 367: except = 0; /* Added by Laurent, but probably wrong way to do it */
! 368: desc = mmu_lookup_pagetable(addr, super, write);
1.1 root 369: #if DEBUG > 2
370: fprintf(stderr, "translate: %x,%u,%u,%u -> %x\n", addr, super, write, data, desc);
371: #endif
1.1.1.2 ! root 372: RESTORE_EXCEPTION;
! 373: // } /* removed by Laurent */
1.1 root 374: CATCH(prb) {
375: RESTORE_EXCEPTION;
376: /* bus error during table search */
377: desc = 0;
378: goto fail;
379: }
380:
381: if ((desc & 1) == 0 || (!super && desc & MMU_MMUSR_S)) {
382: fail:
383: l->valid_data = l->valid_inst = 0;
384: l->global = 0;
385: } else {
386: l->valid_data = l->valid_inst = 1;
387: if (regs.mmu_pagesize_8k)
388: l->phys = (desc & ~0x1fff) - (addr & ~0x1fff);
389: else
390: l->phys = (desc & ~0xfff) - (addr & ~0xfff);
391: l->global = (desc & MMU_MMUSR_G) != 0;
392: l->modified = (desc & MMU_MMUSR_M) != 0;
393: l->write_protect = (desc & MMU_MMUSR_W) != 0;
394: }
395:
396: return desc;
397: }
398:
399: static ALWAYS_INLINE bool mmu_fill_atc_l1(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1)
400: {
401: int idx = ATC_L2_INDEX(addr);
402: int tag = ATC_TAG(addr);
403: struct mmu_atc_line *l = &atc_l2[super ? 1 : 0][idx];
404:
405: if (l->tag != tag) {
406: restart:
407: mmu_fill_atc_l2(addr, super, data, write, l);
408: }
409: if (!(data ? l->valid_data : l->valid_inst)) {
410: fprintf(stderr, "MMU: non-resident page (%x,%x,%x)!\n", addr, regs.pc, regs.fault_pc);
411: goto fail;
412: }
413: if (write) {
414: if (l->write_protect) {
415: fprintf(stderr, "MMU: write protected (via %s) %lx\n", l->tt ? "ttr" : "atc", addr);
416: goto fail;
417: }
418: if (!l->modified)
419: goto restart;
420: }
421: *l1 = *l;
422: #if 0
423: uaecptr phys_addr = addr + l1->phys;
424: if ((phys_addr & 0xfff00000) == 0x00f00000) {
425: l1->hw = 1;
426: goto fail;
427: }
428: if ((phys_addr & 0xfff00000) == 0xfff00000) {
429: l1->hw = 1;
430: l1->phys -= 0xff000000;
431: goto fail;
432: }
433:
434: if (!test_ram_boundary(phys_addr, 1, super, write)) {
435: l1->bus_fault = 1;
436: goto fail;
437: }
438: #endif
439: return true;
440:
441: fail:
442: l1->tag = ~l1->tag;
443: return false;
444: }
445:
446: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write)
447: {
448: struct mmu_atc_line *l;
449:
450: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)];
451: mmu_fill_atc_l2(addr, super, data, write, l);
452: if (!(data ? l->valid_data : l->valid_inst))
1.1.1.2 ! root 453: // THROW(2); /* Removed by Laurent */
! 454: except=2; /* Added by Laurent, probably wrong way to do it */
1.1 root 455:
456: return addr + l->phys;
457: }
458:
459: /*
460: * Lookup the address by walking the page table and updating
461: * the page descriptors accordingly. Returns the found descriptor
462: * or produces a bus error.
463: */
464: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write)
465: {
466: uae_u32 desc, desc_addr, wp;
467: int i;
468:
469: wp = 0;
470: desc = super ? regs.srp : regs.urp;
471:
472: /* fetch root table descriptor */
473: i = (addr >> 23) & 0x1fc;
474: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
475: desc = phys_get_long(desc_addr);
476: if ((desc & 2) == 0) {
477: fprintf(stderr, "MMU: invalid root descriptor for %lx\n", addr);
478: return 0;
479: }
480:
481: wp |= desc;
482: if ((desc & MMU_DES_USED) == 0)
483: phys_put_long(desc_addr, desc | MMU_DES_USED);
484:
485: /* fetch pointer table descriptor */
486: i = (addr >> 16) & 0x1fc;
487: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
488: desc = phys_get_long(desc_addr);
489: if ((desc & 2) == 0) {
490: fprintf(stderr, "MMU: invalid ptr descriptor for %lx\n", addr);
491: return 0;
492: }
493: wp |= desc;
494: if ((desc & MMU_DES_USED) == 0)
495: phys_put_long(desc_addr, desc | MMU_DES_USED);
496:
497: /* fetch page table descriptor */
498: if (regs.mmu_pagesize_8k) {
499: i = (addr >> 11) & 0x7c;
500: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) | i;
501: } else {
502: i = (addr >> 10) & 0xfc;
503: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) | i;
504: }
505:
506: desc = phys_get_long(desc_addr);
507: if ((desc & 3) == 2) {
508: /* indirect */
509: desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
510: desc = phys_get_long(desc_addr);
511: }
512: if ((desc & 1) == 0) {
513: fprintf(stderr, "MMU: invalid page descriptor log=%08lx desc=%08lx @%08lx\n", addr, desc, desc_addr);
514: return desc;
515: }
516:
517: desc |= wp & MMU_DES_WP;
518: if (write) {
519: if (desc & MMU_DES_WP) {
520: if ((desc & MMU_DES_USED) == 0) {
521: desc |= MMU_DES_USED;
522: phys_put_long(desc_addr, desc);
523: }
524: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
525: (MMU_DES_USED|MMU_DES_MODIFIED)) {
526: desc |= MMU_DES_USED|MMU_DES_MODIFIED;
527: phys_put_long(desc_addr, desc);
528: }
529: } else {
530: if ((desc & MMU_DES_USED) == 0) {
531: desc |= MMU_DES_USED;
532: phys_put_long(desc_addr, desc);
533: }
534: }
535: return desc;
536: }
537:
538: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data)
539: {
540: uae_u16 res;
541:
542: res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8;
543: SAVE_EXCEPTION;
1.1.1.2 ! root 544: // TRY(prb) { /* Removed by Laurent */
! 545: except = 0; /* Added by Laurent, probably wrong way */
! 546: res |= mmu_get_byte(addr + 1, data, sz_word);
! 547: RESTORE_EXCEPTION;
! 548: // } /* Removed by Laurent */
1.1 root 549: CATCH(prb) {
550: RESTORE_EXCEPTION;
551: regs.mmu_fault_addr = addr;
552: regs.mmu_ssw |= MMU_SSW_MA;
1.1.1.2 ! root 553: // THROW_AGAIN(prb); /* Removed by Laurent */
! 554: except=2; /* Added by Laurent, probably wrong way */
1.1 root 555: }
556: return res;
557: }
558:
559: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data)
560: {
561: uae_u32 res;
562:
563: if (likely(!(addr & 1))) {
564: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16;
565: SAVE_EXCEPTION;
1.1.1.2 ! root 566: // TRY(prb) { /* Removed by Laurent */
! 567: except = 0; /* Added by Laurent, probably wrong way */
! 568: res |= mmu_get_word(addr + 2, data, sz_long);
! 569: RESTORE_EXCEPTION;
! 570: // } /* Removed by Laurent
1.1 root 571: CATCH(prb) {
572: RESTORE_EXCEPTION;
573: regs.mmu_fault_addr = addr;
574: regs.mmu_ssw |= MMU_SSW_MA;
1.1.1.2 ! root 575: // THROW_AGAIN(prb); /* Removed by Laurent */
! 576: except=2; /* Added by Laurent, ... */
1.1 root 577: }
578: } else {
579: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8;
580: SAVE_EXCEPTION;
1.1.1.2 ! root 581: // TRY(prb) { /* Removed by Laurent */
! 582: except = 0; /* Added by Laurent, probably wrong way */
! 583: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8;
! 584: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8;
! 585: res |= mmu_get_byte(addr + 3, data, sz_long);
! 586: RESTORE_EXCEPTION;
! 587: // } /* Removed by Laurent
1.1 root 588: CATCH(prb) {
589: RESTORE_EXCEPTION;
590: regs.mmu_fault_addr = addr;
591: regs.mmu_ssw |= MMU_SSW_MA;
1.1.1.2 ! root 592: // THROW_AGAIN(prb); /* Removed by Laurent */
! 593: except=2; /* Added by Laurent, ... */
1.1 root 594: }
595: }
596: return res;
597: }
598:
599: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
600: int size, struct mmu_atc_line *cl)
601: {
602: uae_u32 tag = ATC_TAG(addr);
603:
604: if (USETAG && cl->tag == (uae_u16)~tag) {
605: redo:
606: if (cl->hw)
607: return HWget_b(cl->phys + addr);
608: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
609: return 0;
610: }
611:
612: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
613: goto redo;
614:
615: return phys_get_byte(mmu_get_real_address(addr, cl));
616: }
617:
618: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
619: int size, struct mmu_atc_line *cl)
620: {
621: uae_u32 tag = ATC_TAG(addr);
622:
623: if (USETAG && cl->tag == (uae_u16)~tag) {
624: redo:
625: if (cl->hw)
626: return HWget_w(cl->phys + addr);
627: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
628: return 0;
629: }
630:
631: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
632: goto redo;
633:
634: return phys_get_word(mmu_get_real_address(addr, cl));
635: }
636:
637: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
638: int size, struct mmu_atc_line *cl)
639: {
640: uae_u32 tag = ATC_TAG(addr);
641:
642: if (USETAG && cl->tag == (uae_u16)~tag) {
643: redo:
644: if (cl->hw)
645: return HWget_l(cl->phys + addr);
646: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
647: return 0;
648: }
649:
650: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
651: goto redo;
652:
653: return phys_get_long(mmu_get_real_address(addr, cl));
654: }
655:
656: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data)
657: {
658: SAVE_EXCEPTION;
1.1.1.2 ! root 659: // TRY(prb) { /* Removed by Laurent */
! 660: except = 0; /* added by Laurent */
! 661: if (likely(!(addr & 1))) {
! 662: mmu_put_word(addr, val >> 16, data, sz_long);
! 663: mmu_put_word(addr + 2, val, data, sz_long);
! 664: } else {
! 665: mmu_put_byte(addr, val >> 24, data, sz_long);
! 666: mmu_put_byte(addr + 1, val >> 16, data, sz_long);
! 667: mmu_put_byte(addr + 2, val >> 8, data, sz_long);
! 668: mmu_put_byte(addr + 3, val, data, sz_long);
! 669: }
! 670: RESTORE_EXCEPTION;
! 671: // } /* Removed by Laurent */
1.1 root 672: CATCH(prb) {
673: RESTORE_EXCEPTION;
674: regs.wb3_data = val;
675: if (regs.mmu_fault_addr != addr) {
676: regs.mmu_fault_addr = addr;
677: regs.mmu_ssw |= MMU_SSW_MA;
678: }
1.1.1.2 ! root 679: // THROW_AGAIN(prb); /* Removed by Laurent */
1.1 root 680: except=2;
681: }
682: }
683:
684: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data)
685: {
686: SAVE_EXCEPTION;
1.1.1.2 ! root 687: // TRY(prb) { /* Removed by Laurent */
! 688: except = 0; /* added by Laurent */
! 689: mmu_put_byte(addr, val >> 8, data, sz_word);
! 690: mmu_put_byte(addr + 1, val, data, sz_word);
! 691: RESTORE_EXCEPTION;
! 692: // } /* Removed by Laurent */
1.1 root 693: CATCH(prb) {
694: RESTORE_EXCEPTION;
695: regs.wb3_data = val;
696: if (regs.mmu_fault_addr != addr) {
697: regs.mmu_fault_addr = addr;
698: regs.mmu_ssw |= MMU_SSW_MA;
699: }
1.1.1.2 ! root 700: // THROW_AGAIN(prb); /* Removed by Laurent */
! 701: except=2; /* Added by Laurent */
1.1 root 702: }
703: }
704:
705: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
706: int size, struct mmu_atc_line *cl)
707: {
708: uae_u32 tag = ATC_TAG(addr);
709:
710: if (USETAG && cl->tag == (uae_u16)~tag) {
711: redo:
712: if (cl->hw) {
713: HWput_b(cl->phys + addr, val);
714: return;
715: }
716: regs.wb3_data = val;
717: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
718: return;
719: }
720:
721: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
722: goto redo;
723:
724: phys_put_byte(mmu_get_real_address(addr, cl), val);
725: }
726:
727: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
728: int size, struct mmu_atc_line *cl)
729: {
730: uae_u32 tag = ATC_TAG(addr);
731:
732: if (USETAG && cl->tag == (uae_u16)~tag) {
733: redo:
734: if (cl->hw) {
735: HWput_w(cl->phys + addr, val);
736: return;
737: }
738: regs.wb3_data = val;
739: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
740: return;
741: }
742:
743: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
744: goto redo;
745:
746: phys_put_word(mmu_get_real_address(addr, cl), val);
747: }
748:
749: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
750: int size, struct mmu_atc_line *cl)
751: {
752: uae_u32 tag = ATC_TAG(addr);
753:
754: if (USETAG && cl->tag == (uae_u16)~tag) {
755: redo:
756: if (cl->hw) {
757: HWput_l(cl->phys + addr, val);
758: return;
759: }
760: regs.wb3_data = val;
761: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
762: return;
763: }
764:
765: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
766: goto redo;
767:
768: phys_put_long(mmu_get_real_address(addr, cl), val);
769: }
770:
771: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
772: {
773: bool super = (regs.sfc & 4) != 0;
774: bool data = (regs.sfc & 3) != 2;
775: uae_u32 res;
776:
777: if (likely(!is_unaligned(addr, 4)))
778: return mmu_get_user_long(addr, super, data, sz_long);
779:
780: if (likely(!(addr & 1))) {
781: res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16;
782: SAVE_EXCEPTION;
1.1.1.2 ! root 783: // TRY(prb) { /* Removed by Laurent */
! 784: except = 0; /* aded by Laurent */
! 785: res |= mmu_get_user_word(addr + 2, super, data, sz_long);
! 786: RESTORE_EXCEPTION;
! 787: // } /* Removed by Laurent */
1.1 root 788: CATCH(prb) {
789: RESTORE_EXCEPTION;
790: regs.mmu_fault_addr = addr;
791: regs.mmu_ssw |= MMU_SSW_MA;
1.1.1.2 ! root 792: // THROW_AGAIN(prb); /* Removed by Laurent */
! 793: except=2; /* added by Laurent */
1.1 root 794: }
795: } else {
796: res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8;
797: SAVE_EXCEPTION;
1.1.1.2 ! root 798: // TRY(prb) { /* Removed by Laurent */
! 799: except = 0; /* aded by Laurent */
! 800: res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8;
! 801: res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8;
! 802: res |= mmu_get_user_byte(addr + 3, super, data, sz_long);
! 803: RESTORE_EXCEPTION;
! 804: // } /* Removed by Laurent */
1.1 root 805: CATCH(prb) {
806: RESTORE_EXCEPTION;
807: regs.mmu_fault_addr = addr;
808: regs.mmu_ssw |= MMU_SSW_MA;
1.1.1.2 ! root 809: // THROW_AGAIN(prb); /* Removed by Laurent */
! 810: except=2; /* added by Laurent */
1.1 root 811: }
812: }
813: return res;
814: }
815:
816: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
817: {
818: bool super = (regs.sfc & 4) != 0;
819: bool data = (regs.sfc & 3) != 2;
820: uae_u16 res;
821:
822: if (likely(!is_unaligned(addr, 2)))
823: return mmu_get_user_word(addr, super, data, sz_word);
824:
825: res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8;
826: SAVE_EXCEPTION;
1.1.1.2 ! root 827: // TRY(prb) { /* Removed by Laurent */
! 828: except = 0; /* aded by Laurent */
! 829: res |= mmu_get_user_byte(addr + 1, super, data, sz_word);
! 830: RESTORE_EXCEPTION;
! 831: // } /* Removed by Laurent */
1.1 root 832: CATCH(prb) {
833: RESTORE_EXCEPTION;
834: regs.mmu_fault_addr = addr;
835: regs.mmu_ssw |= MMU_SSW_MA;
1.1.1.2 ! root 836: // THROW_AGAIN(prb); /* Removed by Laurent */
! 837: except=2; /* added by Laurent */
1.1 root 838: }
839: return res;
840: }
841:
842: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
843: {
844: bool super = (regs.sfc & 4) != 0;
845: bool data = (regs.sfc & 3) != 2;
846:
847: return mmu_get_user_byte(addr, super, data, sz_byte);
848: }
849:
850: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
851: {
852: bool super = (regs.dfc & 4) != 0;
853: bool data = (regs.dfc & 3) != 2;
854:
855: SAVE_EXCEPTION;
1.1.1.2 ! root 856: // TRY(prb) { /* Removed by Laurent */
! 857: except = 0; /* aded by Laurent */
! 858: if (likely(!is_unaligned(addr, 4)))
! 859: mmu_put_user_long(addr, val, super, data, sz_long);
! 860: else if (likely(!(addr & 1))) {
! 861: mmu_put_user_word(addr, val >> 16, super, data, sz_long);
! 862: mmu_put_user_word(addr + 2, val, super, data, sz_long);
! 863: } else {
! 864: mmu_put_user_byte(addr, val >> 24, super, data, sz_long);
! 865: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long);
! 866: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long);
! 867: mmu_put_user_byte(addr + 3, val, super, data, sz_long);
! 868: }
! 869: RESTORE_EXCEPTION;
! 870: // } /* Removed by Laurent */
1.1 root 871: CATCH(prb) {
872: RESTORE_EXCEPTION;
873: regs.wb3_data = val;
874: if (regs.mmu_fault_addr != addr) {
875: regs.mmu_fault_addr = addr;
876: regs.mmu_ssw |= MMU_SSW_MA;
877: }
1.1.1.2 ! root 878: // THROW_AGAIN(prb); /* Removed by Laurent */
! 879: except=2; /* added by Laurent */
1.1 root 880: }
881: }
882:
883: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
884: {
885: bool super = (regs.dfc & 4) != 0;
886: bool data = (regs.dfc & 3) != 2;
887:
888: SAVE_EXCEPTION;
1.1.1.2 ! root 889: // TRY(prb) { /* Removed by Laurent */
! 890: except = 0; /* aded by Laurent */
! 891: if (likely(!is_unaligned(addr, 2)))
! 892: mmu_put_user_word(addr, val, super, data, sz_word);
! 893: else {
! 894: mmu_put_user_byte(addr, val >> 8, super, data, sz_word);
! 895: mmu_put_user_byte(addr + 1, val, super, data, sz_word);
! 896: }
! 897: RESTORE_EXCEPTION;
! 898: // } /* Removed by Laurent */
1.1 root 899: CATCH(prb) {
900: RESTORE_EXCEPTION;
901: regs.wb3_data = val;
902: if (regs.mmu_fault_addr != addr) {
903: regs.mmu_fault_addr = addr;
904: regs.mmu_ssw |= MMU_SSW_MA;
905: }
1.1.1.2 ! root 906: // THROW_AGAIN(prb); /* Removed by Laurent */
! 907: except=2; /* added by Laurent */
1.1 root 908: }
909: }
910:
911: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
912: {
913: bool super = (regs.dfc & 4) != 0;
914: bool data = (regs.dfc & 3) != 2;
915:
916: SAVE_EXCEPTION;
1.1.1.2 ! root 917: // TRY(prb) { /* Removed by Laurent */
! 918: except = 0; /* aded by Laurent */
! 919: mmu_put_user_byte(addr, val, super, data, sz_byte);
! 920: RESTORE_EXCEPTION;
! 921: // } /* Removed by Laurent */
1.1 root 922: CATCH(prb) {
923: RESTORE_EXCEPTION;
924: regs.wb3_data = val;
1.1.1.2 ! root 925: // THROW_AGAIN(prb); /* Removed by Laurent */
! 926: except=2; /* added by Laurent */
1.1 root 927: }
928: }
929:
930: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
931: {
932: bool super = (regs.dfc & 4) != 0;
933: DUNUSED(extra);
934: if ((opcode & 0xFE0) == 0x0500) {
935: bool glob;
936: int regno;
937: //D(didflush = 0);
938: uae_u32 addr;
939: /* PFLUSH */
940: regno = opcode & 7;
941: glob = (opcode & 8) != 0;
942:
943: if (opcode & 16) {
944: fprintf(stderr, "pflusha(%u,%u)\n", glob, regs.dfc);
945: mmu_flush_atc_all(glob);
946: } else {
947: addr = m68k_areg(regs, regno);
948: fprintf(stderr, "pflush(%u,%u,%x)\n", glob, regs.dfc, addr);
949: mmu_flush_atc(addr, super, glob);
950: }
951: flush_internals();
952: #ifdef USE_JIT
953: flush_icache(0);
954: #endif
955: } else if ((opcode & 0x0FD8) == 0x548) {
956: bool write;
957: int regno;
958: uae_u32 addr;
959:
960: regno = opcode & 7;
961: write = (opcode & 32) == 0;
962: addr = m68k_areg(regs, regno);
963: fprintf(stderr, "PTEST%c (A%d) %08x DFC=%d\n", write ? 'W' : 'R', regno, addr, regs.dfc);
964: mmu_flush_atc(addr, super, true);
965: SAVE_EXCEPTION;
1.1.1.2 ! root 966: // TRY(prb) { /* Removed by Laurent */
! 967: except = 0; /* aded by Laurent */
1.1 root 968: struct mmu_atc_line *l;
969: uae_u32 desc;
970: bool data = (regs.dfc & 3) != 2;
971:
972: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)];
973: desc = mmu_fill_atc_l2(addr, super, data, write, l);
974: if (!(data ? l->valid_data : l->valid_inst))
975: regs.mmusr = MMU_MMUSR_B;
976: else if (l->tt)
977: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
978: else {
979: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|
980: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W);
981: regs.mmusr |= MMU_MMUSR_R;
982: }
1.1.1.2 ! root 983: // } /* Removed by Laurent */
1.1 root 984: CATCH(prb) {
985: regs.mmusr = MMU_MMUSR_B;
986: }
987: RESTORE_EXCEPTION;
988: fprintf(stderr, "PTEST result: mmusr %08x\n", regs.mmusr);
989: } else
990: op_illg (opcode);
991: }
992:
993: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
994: {
995: struct mmu_atc_line *l;
996: int i, j;
997:
998: l = atc_l1[super ? 1 : 0][0][0];
999: i = ATC_L1_INDEX(addr);
1000: for (j = 0; j < 4; j++) {
1001: if (global || !l[i].global)
1002: l[i].tag = 0x8000;
1003: l += ATC_L1_SIZE;
1004: }
1005: if (regs.mmu_pagesize_8k) {
1006: i = ATC_L1_INDEX(addr) ^ 1;
1007: for (j = 0; j < 4; j++) {
1008: if (global || !l[i].global)
1009: l[i].tag = 0x8000;
1010: l += ATC_L1_SIZE;
1011: }
1012: }
1013: l = atc_l2[super ? 1 : 0];
1014: i = ATC_L2_INDEX(addr);
1015: if (global || !l[i].global)
1016: l[i].tag = 0x8000;
1017: if (regs.mmu_pagesize_8k) {
1018: i ^= 1;
1019: if (global || !l[i].global)
1020: l[i].tag = 0x8000;
1021: }
1022: }
1023:
1024: void REGPARAM2 mmu_flush_atc_all(bool global)
1025: {
1026: struct mmu_atc_line *l;
1027: unsigned int i;
1028:
1029: l = atc_l1[0][0][0];
1030: for (i = 0; i < sizeof(atc_l1) / sizeof(*l); l++, i++) {
1031: if (global || !l->global)
1032: l->tag = 0x8000;
1033: }
1034:
1035: l = atc_l2[0];
1036: for (i = 0; i < sizeof(atc_l2) / sizeof(*l); l++, i++) {
1037: if (global || !l->global)
1038: l->tag = 0x8000;
1039: }
1040: }
1041:
1042: void REGPARAM2 mmu_reset(void)
1043: {
1044: mmu_flush_atc_all(true);
1045: #if 0
1046: regs.urp = regs.srp = 0;
1047: regs.itt0 = regs.itt0 = 0;
1048: regs.dtt0 = regs.dtt0 = 0;
1049: regs.mmusr = 0;
1050: #endif
1051: }
1052:
1053:
1054: void REGPARAM2 mmu_set_tc(uae_u16 tc)
1055: {
1056: #if 0
1057: if (regs.tcr == tc)
1058: return;
1059: regs.tcr = tc;
1060: #endif
1061: regs.mmu_enabled = tc & 0x8000 ? 1 : 0;
1062: regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0;
1063: mmu_flush_atc_all(true);
1064:
1065: write_log("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k);
1066: }
1067:
1068: void REGPARAM2 mmu_set_super(bool super)
1069: {
1070: current_atc = &atc_l1[super ? 1 : 0];
1071: }
1072:
1073: #else
1074:
1075: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
1076: {
1077: if ((opcode & 0xFE0) == 0x0500) {
1078: /* PFLUSH instruction */
1079: flush_internals();
1080: } else if ((opcode & 0x0FD8) == 0x548) {
1081: /* PTEST instruction */
1082: } else
1083: op_illg(opcode);
1084: }
1085:
1086: #endif
1087:
1088: /*
1089: vim:ts=4:sw=4:
1090: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.