]> git.sesse.net Git - pistorm/blob - m68kmmu.h
Merge pull request #34 from paulofduarte/wip-crap
[pistorm] / m68kmmu.h
1 /*
2     m68kmmu.h - PMMU implementation for 68851/68030/68040
3
4     By R. Belmont
5
6     Copyright Nicola Salmoria and the MAME Team.
7     Visit http://mamedev.org for licensing and usage restrictions.
8 */
9
10 // MMU status register bit definitions
11
12 #if 0
13 #define MMULOG(A) printf A
14 #else
15 #define MMULOG(...)
16 #endif
17 #if 1
18 #define logerror printf
19 #else
20 #define logerror(...)
21 #endif
22
23 // MMU SR register fields
24 #define M68K_MMU_SR_BUS_ERROR        0x8000
25 #define M68K_MMU_SR_SUPERVISOR_ONLY  0x2000
26 #define M68K_MMU_SR_WRITE_PROTECT    0x0800
27 #define M68K_MMU_SR_INVALID          0x0400
28 #define M68K_MMU_SR_MODIFIED         0x0200
29 #define M68K_MMU_SR_TRANSPARENT      0x0040
30
31 // MMU translation table descriptor field definitions
32 #define M68K_MMU_DF_DT               0x00000003
33 #define M68K_MMU_DF_DT_INVALID       0x00000000
34 #define M68K_MMU_DF_DT_PAGE          0x00000001
35 #define M68K_MMU_DF_DT_TABLE_4BYTE   0x00000002
36 #define M68K_MMU_DF_DT_TABLE_8BYTE   0x00000003
37 #define M68K_MMU_DF_WP               0x00000004
38 #define M68K_MMU_DF_USED             0x00000008
39 #define M68K_MMU_DF_MODIFIED         0x00000010
40 #define M68K_MMU_DF_CI               0x00000040
41 #define M68K_MMU_DF_SUPERVISOR       0x00000100
42 #define M68K_MMU_DF_ADDR_MASK        0xfffffff0
43 #define M68K_MMU_DF_IND_ADDR_MASK    0xfffffffc
44
45 // MMU ATC Fields
46 #define M68K_MMU_ATC_BUSERROR        0x08000000
47 #define M68K_MMU_ATC_CACHE_IN        0x04000000
48 #define M68K_MMU_ATC_WRITE_PR        0x02000000
49 #define M68K_MMU_ATC_MODIFIED        0x01000000
50 #define M68K_MMU_ATC_MASK            0x00ffffff
51 #define M68K_MMU_ATC_SHIFT           8
52 #define M68K_MMU_ATC_VALID           0x08000000
53
54 // MMU Translation Control register
55 #define M68K_MMU_TC_SRE              0x02000000
56 #define M68K_MMU_TC_FCL              0x01000000
57
58 // TT register
59 #define M68K_MMU_TT_ENABLE           0x8000
60
61 #define m_side_effects_disabled 0
62
63 /* decodes the effective address */
64 uint32 DECODE_EA_32(int ea)
65 {
66         int mode = (ea >> 3) & 0x7;
67         int reg = (ea & 0x7);
68
69         switch (mode)
70         {
71                 case 2:     // (An)
72                 {
73                         return REG_A[reg];
74                 }
75                 case 3:     // (An)+
76                 {
77                         uint32 ea = EA_AY_PI_32();
78                         return ea;
79                 }
80                 case 5:     // (d16, An)
81                 {
82                         uint32 ea = EA_AY_DI_32();
83                         return ea;
84                 }
85                 case 6:     // (An) + (Xn) + d8
86                 {
87                         uint32 ea = EA_AY_IX_32();
88                         return ea;
89                 }
90                 case 7:
91                 {
92                         switch (reg)
93                         {
94                                 case 0:     // (xxx).W
95                                 {
96                                         uint32 ea = OPER_I_16();
97                                         return ea;
98                                 }
99                                 case 1:     // (xxx).L
100                                 {
101                                         uint32 d1 = OPER_I_16();
102                                         uint32 d2 = OPER_I_16();
103                                         uint32 ea = (d1 << 16) | d2;
104                                         return ea;
105                                 }
106                                 case 2:     // (d16, PC)
107                                 {
108                                         uint32 ea = EA_PCDI_32();
109                                         return ea;
110                                 }
111                                 default:    fatalerror("m68k: DECODE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
112                         }
113                         break;
114                 }
115                 default:    fatalerror("m68k: DECODE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
116         }
117         return 0;
118 }
119
120 void pmmu_set_buserror(uint32 addr_in)
121 {
122         if (!m_side_effects_disabled && ++m68ki_cpu.mmu_tmp_buserror_occurred == 1)
123         {
124                 m68ki_cpu.mmu_tmp_buserror_address = addr_in;
125                 m68ki_cpu.mmu_tmp_buserror_rw = m68ki_cpu.mmu_tmp_rw;
126                 m68ki_cpu.mmu_tmp_buserror_fc = m68ki_cpu.mmu_tmp_fc;
127                 m68ki_cpu.mmu_tmp_buserror_sz = m68ki_cpu.mmu_tmp_sz;
128         }
129 }
130
131
132 // pmmu_atc_add: adds this address to the ATC
133 void pmmu_atc_add(uint32 logical, uint32 physical, int fc, int rw)
134 {
135         // get page size (i.e. # of bits to ignore); is 10 for Apollo
136         int ps = (m68ki_cpu.mmu_tc >> 20) & 0xf;
137         uint32 atc_tag = M68K_MMU_ATC_VALID | ((fc & 7) << 24) | ((logical >> ps) << (ps - 8));
138         uint32 atc_data = (physical >> ps) << (ps - 8);
139
140         if (m68ki_cpu.mmu_tmp_sr & (M68K_MMU_SR_BUS_ERROR|M68K_MMU_SR_INVALID|M68K_MMU_SR_SUPERVISOR_ONLY))
141         {
142                 atc_data |= M68K_MMU_ATC_BUSERROR;
143         }
144
145         if (m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)
146         {
147                 atc_data |= M68K_MMU_ATC_WRITE_PR;
148         }
149
150         if (!rw && !(m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
151         {
152                 atc_data |= M68K_MMU_ATC_MODIFIED;
153         }
154
155         // first see if this is already in the cache
156         for (int i = 0; i < MMU_ATC_ENTRIES; i++)
157         {
158                 // if tag bits and function code match, don't add
159                 if (m68ki_cpu.mmu_atc_tag[i] == atc_tag)
160                 {
161                         MMULOG(("%s: hit, old %08x new %08x\n", __func__, m68ki_cpu.mmu_atc_data[i], atc_data));
162                         m68ki_cpu.mmu_atc_data[i] = atc_data;
163                         return;
164                 }
165         }
166
167         // find an open entry
168         int found = -1;
169         for (int i = 0; i < MMU_ATC_ENTRIES; i++)
170         {
171                 if (!(m68ki_cpu.mmu_atc_tag[i] & M68K_MMU_ATC_VALID))
172                 {
173                         found = i;
174                         break;
175                 }
176         }
177
178         // did we find an entry?  steal one by round-robin then
179         if (found == -1)
180         {
181                 found = m68ki_cpu.mmu_atc_rr++;
182
183                 if (m68ki_cpu.mmu_atc_rr >= MMU_ATC_ENTRIES)
184                 {
185                         m68ki_cpu.mmu_atc_rr = 0;
186                 }
187         }
188
189         // add the entry
190         MMULOG(("ATC[%2d] add: log %08x -> phys %08x (fc=%d) data=%08x\n",
191                         found, (logical >> ps) << ps, (physical >> ps) << ps, fc, atc_data));
192         m68ki_cpu.mmu_atc_tag[found] = atc_tag;
193         m68ki_cpu.mmu_atc_data[found] = atc_data;
194 }
195
196 // pmmu_atc_flush: flush entire ATC
197 // 7fff0003 001ffd10 80f05750 is what should load
198 void pmmu_atc_flush()
199 {
200         MMULOG(("ATC flush: pc=%08x\n", m68ki_cpu.ppc));
201 //      std::fill(std::begin(m68ki_cpu.mmu_atc_tag), std::end(m68ki_cpu.mmu_atc_tag), 0);
202         for(int i=0;i<MMU_ATC_ENTRIES;i++)
203                 m68ki_cpu.mmu_atc_tag[i]=0;
204         m68ki_cpu.mmu_atc_rr = 0;
205 }
206
207 int fc_from_modes(uint16 modes);
208
209 void pmmu_atc_flush_fc_ea(uint16 modes)
210 {
211         unsigned int fcmask = (modes >> 5) & 7;
212         unsigned int fc = fc_from_modes(modes) & fcmask;
213         unsigned int ps = (m68ki_cpu.mmu_tc >> 20) & 0xf;
214         unsigned int mode = (modes >> 10) & 7;
215         uint32 ea;
216
217         switch (mode)
218         {
219         case 1: // PFLUSHA
220                 MMULOG(("PFLUSHA: mode %d\n", mode));
221                 pmmu_atc_flush();
222                 break;
223
224         case 4: // flush by fc
225                 MMULOG(("flush by fc: %d, mask %d\n", fc, fcmask));
226                 for(int i=0,e;i<MMU_ATC_ENTRIES;i++)
227                 {
228                         e=m68ki_cpu.mmu_atc_tag[i];
229                         if ((e & M68K_MMU_ATC_VALID) && ((e >> 24) & fcmask) == fc)
230                         {
231                                 MMULOG(("flushing entry %08x\n", e));
232                                 m68ki_cpu.mmu_atc_tag[i] = 0;
233                         }
234                 }
235                 break;
236
237         case 6: // flush by fc + ea
238
239                 ea = DECODE_EA_32(m68ki_cpu.ir);
240                 MMULOG(("flush by fc/ea: fc %d, mask %d, ea %08x\n", fc, fcmask, ea));
241                 for(unsigned int i=0,e;i<MMU_ATC_ENTRIES;i++)
242                 {
243                         e=m68ki_cpu.mmu_atc_tag[i];
244                         if ((e & M68K_MMU_ATC_VALID) &&
245                                 (((e >> 24) & fcmask) == fc) &&
246 //              (((e >> ps) << (ps - 8)) == ((ea >> ps) << (ps - 8))))
247                                 ( (e << ps) == (ea >> 8 << ps) ))
248                         {
249                                 MMULOG(("flushing entry %08x\n", e));
250                                 m68ki_cpu.mmu_atc_tag[i] = 0;
251                         }
252                 }
253                 break;
254
255         default:
256                 logerror("PFLUSH mode %d not supported\n", mode);
257                 break;
258         }
259 }
260
261 //template<bool ptest>
262 uint16 pmmu_atc_lookup(uint32 addr_in, int fc, uint16 rw,
263                                          uint32 *addr_out,int ptest)
264 {
265         MMULOG(("%s: LOOKUP addr_in=%08x, fc=%d, ptest=%d, rw=%d\n", __func__, addr_in, fc, ptest,rw));
266         unsigned int ps = (m68ki_cpu.mmu_tc >> 20) & 0xf;
267         uint32 atc_tag = M68K_MMU_ATC_VALID | ((fc & 7) << 24) | ((addr_in >> ps) << (ps - 8));
268
269         for (int i = 0; i < MMU_ATC_ENTRIES; i++)
270         {
271
272                 if (m68ki_cpu.mmu_atc_tag[i] != atc_tag)
273                 {
274                         continue;
275                 }
276                 
277                 uint32 atc_data = m68ki_cpu.mmu_atc_data[i];
278
279                 if (!ptest && !rw)
280                 {
281                         // According to MC86030UM:
282                         // "If the M bit is clear and a write access to this logical
283                         // address is attempted, the MC68030 aborts the access and initiates a table
284                         // search, setting the M bit in the page descriptor, invalidating the old ATC
285                         // entry, and creating a new entry with the M bit set.
286                         if (!(atc_data & M68K_MMU_ATC_MODIFIED))
287                         {
288                                 m68ki_cpu.mmu_atc_tag[i] = 0;
289                                 continue;
290                         }
291                 }
292
293                 m68ki_cpu.mmu_tmp_sr = 0;
294                 if (atc_data & M68K_MMU_ATC_MODIFIED)
295                 {
296                         m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_MODIFIED;
297                 }
298
299                 if (atc_data & M68K_MMU_ATC_WRITE_PR)
300                 {
301                         m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_WRITE_PROTECT;
302                 }
303
304                 if (atc_data & M68K_MMU_ATC_BUSERROR)
305                 {
306                         m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_BUS_ERROR|M68K_MMU_SR_INVALID;
307                 }
308                 *addr_out = (atc_data << 8) | (addr_in & ~(((uint32)~0) << ps));
309                 MMULOG(("%s: addr_in=%08x, addr_out=%08x, MMU SR %04x\n",
310                                 __func__, addr_in, *addr_out, m68ki_cpu.mmu_tmp_sr));
311                 return 1;
312         }
313         MMULOG(("%s: lookup failed\n", __func__));
314         if (ptest)
315         {
316                 m68ki_cpu.mmu_tmp_sr = M68K_MMU_SR_INVALID;
317         }
318         return 0;
319 }
320
321 uint16 pmmu_match_tt(uint32 addr_in, int fc, uint32 tt, uint16 rw)
322 {
323         if (!(tt & M68K_MMU_TT_ENABLE))
324         {
325                 return 0;
326         }
327
328         // transparent translation enabled
329         uint32 address_base = tt & 0xff000000;
330         uint32 address_mask = ((tt << 8) & 0xff000000) ^ 0xff000000;
331         uint32 fcmask = (~tt) & 7;
332         uint32 fcbits = (tt >> 4) & 7;
333         uint16 rwmask = !!(~tt & 0x100);
334         uint16 rwbit = !!(tt & 0x200);
335
336         if ((addr_in & address_mask) != (address_base & address_mask))
337         {
338                 return 0;
339         }
340
341         if ((fc & fcmask) != (fcbits & fcmask))
342         {
343                 return 0;
344         }
345
346         if ((rw & rwmask) != (rwbit & rwmask))
347         {
348                 return 0;
349         }
350
351         m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_TRANSPARENT;
352         return 1;
353 }
354
355 void update_descriptor(uint32 tptr, int type, uint32 entry, int16 rw)
356 {
357         if (type == M68K_MMU_DF_DT_PAGE && !rw &&
358                         !(entry & M68K_MMU_DF_MODIFIED) &&
359                         !(entry & M68K_MMU_DF_WP))
360         {
361                 MMULOG(("%s: set M+U at %08x\n", __func__, tptr));
362                 m68k_write_memory_32(tptr, entry | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED);
363         }
364         else if (type != M68K_MMU_DF_DT_INVALID && !(entry & M68K_MMU_DF_USED))
365         {
366                 MMULOG(("%s: set U at %08x\n", __func__, tptr));
367                 m68k_write_memory_32(tptr, entry | M68K_MMU_DF_USED);
368         }
369 }
370
371
372 //template<bool _long>
373 void update_sr(int type, uint32 tbl_entry, int fc,uint16 _long)
374 {
375         if (m_side_effects_disabled)
376         {
377                 return;
378         }
379
380         switch(type)
381         {
382         case M68K_MMU_DF_DT_INVALID:
383                 // Invalid has no flags
384                 break;
385
386         case M68K_MMU_DF_DT_PAGE:
387                 if (tbl_entry & M68K_MMU_DF_MODIFIED)
388                 {
389                         m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_MODIFIED;
390                 }
391                 /* FALLTHROUGH */
392
393         case M68K_MMU_DF_DT_TABLE_4BYTE:
394                 /* FALLTHROUGH */
395
396         case M68K_MMU_DF_DT_TABLE_8BYTE:
397
398                 if (tbl_entry & M68K_MMU_DF_WP)
399                 {
400                         m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_WRITE_PROTECT;
401                 }
402
403                 if (_long && !(fc & 4) && (tbl_entry & M68K_MMU_DF_SUPERVISOR))
404                 {
405                         m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_SUPERVISOR_ONLY;
406                 }
407                 break;
408         default:
409                 break;
410         }
411 }
412
413 //template<bool ptest>
414 uint16 pmmu_walk_tables(uint32 addr_in, int type, uint32 table, uint8 fc,
415                                                 int limit, uint16 rw, uint32 *addr_out, int ptest)
416 {
417         int level = 0;
418         uint32 bits = m68ki_cpu.mmu_tc & 0xffff;
419         int pagesize = (m68ki_cpu.mmu_tc >> 20) & 0xf;
420         int is = (m68ki_cpu.mmu_tc >> 16) & 0xf;
421         int bitpos = 12;
422         int resolved = 0;
423         int pageshift = is;
424
425         addr_in <<= is;
426
427         m68ki_cpu.mmu_tablewalk = 1;
428
429         if (m68ki_cpu.mmu_tc & M68K_MMU_TC_FCL)
430         {
431                 bitpos = 16;
432         }
433
434         do
435         {
436                 int indexbits = (bits >> bitpos) & 0xf;
437                 int table_index  = (bitpos == 16) ? fc : (addr_in >> (32 - indexbits));
438                 bitpos -= 4;
439                 uint16 indirect = (!bitpos || !(bits >> bitpos)) && indexbits;
440                 uint32 tbl_entry, tbl_entry2;
441
442                 MMULOG(("%s: type %d, table %08x, addr_in %08x, indexbits %d, pageshift %d, indirect %d table_index %08x, rw=%d fc=%d\n",
443                                 __func__, type, table, addr_in, indexbits, pageshift, indirect, table_index, rw, fc));
444
445                 switch(type)
446                 {
447                         case M68K_MMU_DF_DT_INVALID:   // invalid, will cause MMU exception
448                                 m68ki_cpu.mmu_tmp_sr = M68K_MMU_SR_INVALID;
449                                 MMULOG(("PMMU: DT0 PC=%x (addr_in %08x -> %08x)\n", m68ki_cpu.ppc, addr_in, *addr_out));
450                                 resolved = 1;
451                                 break;
452
453                         case M68K_MMU_DF_DT_PAGE:   // page descriptor, will cause direct mapping
454                                 if (!ptest)
455                                 {
456                                         table &= ((uint32)~0) << pagesize;
457                                         *addr_out = table + (addr_in >> pageshift);
458                                 }
459                                 resolved = 1;
460                                 break;
461
462                         case M68K_MMU_DF_DT_TABLE_4BYTE:   // valid 4 byte descriptors
463                                 level++;
464                                 *addr_out = table + (table_index << 2);
465                                 tbl_entry = m68k_read_memory_32(*addr_out);
466                                 type = tbl_entry & M68K_MMU_DF_DT;
467
468                                 if (indirect && (type == 2 || type == 3))
469                                 {
470                                         level++;
471                                         MMULOG(("SHORT INDIRECT DESC: %08x\n", tbl_entry));
472                                         *addr_out = tbl_entry & M68K_MMU_DF_IND_ADDR_MASK;
473                                         tbl_entry = m68k_read_memory_32(*addr_out);
474                                         type = tbl_entry & M68K_MMU_DF_DT;
475                                 }
476
477                                 MMULOG(("SHORT DESC: %08x\n", tbl_entry));
478                                 table = tbl_entry & M68K_MMU_DF_ADDR_MASK;
479                                 if (!m_side_effects_disabled)
480                                 {
481                                         update_sr(type, tbl_entry, fc,0);
482                                         if (!ptest)
483                                         {
484                                                 update_descriptor(*addr_out, type, tbl_entry, rw);
485                                         }
486                                 }
487                                 break;
488
489                         case M68K_MMU_DF_DT_TABLE_8BYTE:   // valid 8 byte descriptors
490                                 level++;
491                                 *addr_out = table + (table_index << 3);
492                                 tbl_entry = m68k_read_memory_32(*addr_out);
493                                 tbl_entry2 = m68k_read_memory_32((*addr_out) + 4);
494                                 type = tbl_entry & M68K_MMU_DF_DT;
495
496                                 if (indirect && (type == 2 || type == 3))
497                                 {
498                                         level++;
499                                         MMULOG(("LONG INDIRECT DESC: %08x%08x\n", tbl_entry, tbl_entry2));
500                                         *addr_out = tbl_entry2 & M68K_MMU_DF_IND_ADDR_MASK;
501                                         tbl_entry = m68k_read_memory_32(*addr_out);
502                                         tbl_entry2 = m68k_read_memory_32(*addr_out);
503                                         type = tbl_entry & M68K_MMU_DF_DT;
504                                 }
505
506                                 MMULOG(("LONG DESC: %08x %08x\n", tbl_entry, tbl_entry2));
507                                 table = tbl_entry2 & M68K_MMU_DF_ADDR_MASK;
508                                 if (!m_side_effects_disabled)
509                                 {
510                                         update_sr(type, tbl_entry, fc,1);
511                                         if (!ptest)
512                                         {
513                                                 update_descriptor(*addr_out, type, tbl_entry, rw);
514                                         }
515                                 }
516                                 break;
517                 }
518
519                 if (m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_BUS_ERROR)
520                 {
521                         // Bus error during page table walking is always fatal
522                         resolved = 1;
523                         break;
524                 }
525
526                 if (!ptest && !m_side_effects_disabled)
527                 {
528                         if (!rw && (m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
529                         {
530                                 resolved = 1;
531                                 break;
532                         }
533
534                         if (!(fc & 4) && (m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_SUPERVISOR_ONLY))
535                         {
536                                 resolved = 1;
537                                 break;
538                         }
539
540                 }
541                 addr_in <<= indexbits;
542                 pageshift += indexbits;
543         } while(level < limit && !resolved);
544
545
546         m68ki_cpu.mmu_tmp_sr &= 0xfff0;
547         m68ki_cpu.mmu_tmp_sr |= level;
548         MMULOG(("MMU SR after walk: %04X\n", m68ki_cpu.mmu_tmp_sr));
549         m68ki_cpu.mmu_tablewalk = 0;
550         return resolved;
551 }
552
553 // pmmu_translate_addr_with_fc: perform 68851/68030-style PMMU address translation
554 //template<bool ptest, bool pload>
555 uint32 pmmu_translate_addr_with_fc(uint32 addr_in, uint8 fc, uint16 rw, int limit,int ptest,int pload)
556 {
557         uint32 addr_out = 0;
558
559
560         MMULOG(("%s: addr_in=%08x, fc=%d, ptest=%d, rw=%d, limit=%d, pload=%d\n",
561                         __func__, addr_in, fc, ptest, rw, limit, pload));
562         m68ki_cpu.mmu_tmp_sr = 0;
563
564         m68ki_cpu.mmu_last_logical_addr = addr_in;
565
566         if (pmmu_match_tt(addr_in, fc, m68ki_cpu.mmu_tt0, rw) ||
567                 pmmu_match_tt(addr_in, fc, m68ki_cpu.mmu_tt1, rw) ||
568                 fc == 7)
569         {
570                 return addr_in;
571         }
572
573         if (ptest && limit == 0)
574         {
575                 pmmu_atc_lookup(addr_in, fc, rw, &addr_out, 1);
576                 return addr_out;
577         }
578
579         if (!ptest && !pload && pmmu_atc_lookup(addr_in, fc, rw, &addr_out, 0))
580         {
581                 if ((m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_BUS_ERROR) || (!rw && (m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)))
582                 {
583                         MMULOG(("set atc hit buserror: addr_in=%08x, addr_out=%x, rw=%x, fc=%d, sz=%d\n",
584                                         addr_in, addr_out, m68ki_cpu.mmu_tmp_rw, m68ki_cpu.mmu_tmp_fc, m68ki_cpu.mmu_tmp_sz));
585                         pmmu_set_buserror(addr_in);
586                 }
587                 return addr_out;
588         }
589
590         int type;
591         uint32 tbl_addr;
592         // if SRP is enabled and we're in supervisor mode, use it
593         if ((m68ki_cpu.mmu_tc & M68K_MMU_TC_SRE) && (fc & 4))
594         {
595                 tbl_addr = m68ki_cpu.mmu_srp_aptr & M68K_MMU_DF_ADDR_MASK;
596                 type = m68ki_cpu.mmu_srp_limit & M68K_MMU_DF_DT;
597         }
598         else    // else use the CRP
599         {
600                 tbl_addr = m68ki_cpu.mmu_crp_aptr & M68K_MMU_DF_ADDR_MASK;
601                 type = m68ki_cpu.mmu_crp_limit & M68K_MMU_DF_DT;
602         }
603
604         if (!pmmu_walk_tables(addr_in, type, tbl_addr, fc, limit, rw, &addr_out, ptest))
605         {
606                 MMULOG(("%s: addr_in=%08x, type=%x, tbl_addr=%x, fc=%d, limit=%x, rw=%x, addr_out=%x, ptest=%d\n",
607                                 __func__, addr_in, type, tbl_addr, fc, limit, rw, addr_out, ptest));
608                 fatalerror("Table walk did not resolve\n");
609         }
610
611         if (ptest)
612         {
613                 return addr_out;
614         }
615
616         if ((m68ki_cpu.mmu_tmp_sr & (M68K_MMU_SR_INVALID|M68K_MMU_SR_SUPERVISOR_ONLY)) ||
617                         ((m68ki_cpu.mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT) && !rw))
618         {
619
620                 if (!pload)
621                 {
622                         MMULOG(("%s: set buserror (SR %04X)\n", __func__, m68ki_cpu.mmu_tmp_sr));
623                         pmmu_set_buserror(addr_in);
624                 }
625         }
626
627         // it seems like at least the 68030 sets the M bit in the MMU SR
628         // if the root descriptor is of PAGE type, so do a logical and
629         // between RW and the root type
630         if (!m_side_effects_disabled)
631         {
632                 pmmu_atc_add(addr_in, addr_out, fc, rw && type != 1);
633         }
634         MMULOG(("PMMU: [%08x] => [%08x] (SR %04x)\n", addr_in, addr_out, m68ki_cpu.mmu_tmp_sr));
635         return addr_out;
636 }
637
638 // FC bits: 2 = supervisor, 1 = program, 0 = data
639 // the 68040 is a subset of the 68851 and 68030 PMMUs - the page table sizes are fixed, there is no early termination, etc, etc.
640 uint32 pmmu_translate_addr_with_fc_040(uint32 addr_in, uint8 fc, uint8 ptest)
641 {
642         uint32 addr_out, tt0, tt1;
643
644         addr_out = addr_in;
645         m68ki_cpu.mmu_tmp_sr = 0;
646
647         // transparent translation registers are always in force even if the PMMU itself is disabled
648         // they don't do much in emulation because we never write out of order, but the write-protect and cache control features
649         // are emulatable, and apparently transparent translation regions skip the page table lookup.
650         if (fc & 1) // data, use DTT0/DTT1
651         {
652                 tt0 = m68ki_cpu.mmu_dtt0;
653                 tt1 = m68ki_cpu.mmu_dtt1;
654         }
655         else if (fc & 2)    // program, use ITT0/ITT1
656         {
657                 tt0 = m68ki_cpu.mmu_itt0;
658                 tt1 = m68ki_cpu.mmu_itt1;
659         }
660         else
661         {
662                 fatalerror("68040: function code %d is neither data nor program!\n", fc & 7);
663         }
664
665         if (tt0 & M68K_MMU_TT_ENABLE)
666         {
667                 int fcmask[4] = { 4, 4, 0, 0 };
668                 int fcmatch[4] = { 0, 4, 0, 0 };
669                 uint32 mask = (tt0 >> 16) & 0xff;
670                 mask ^= 0xff;
671                 mask <<= 24;
672
673                 if ((addr_in & mask) == (tt0 & mask) && (fc & fcmask[(tt0 >> 13) & 3]) == fcmatch[(tt0 >> 13) & 3])
674                 {
675                         MMULOG(("TT0 match on address %08x (TT0 = %08x, mask = %08x)\n", addr_in, tt0, mask));
676                         if ((tt0 & 4) && !m68ki_cpu.mmu_tmp_rw && !ptest)   // write protect?
677                         {
678                                 pmmu_set_buserror(addr_in);
679                         }
680
681                         return addr_in;
682                 }
683         }
684
685         if (tt1 & M68K_MMU_TT_ENABLE)
686         {
687                 static int fcmask[4] = { 4, 4, 0, 0 };
688                 static int fcmatch[4] = { 0, 4, 0, 0 };
689                 uint32 mask = (tt1 >> 16) & 0xff;
690                 mask ^= 0xff;
691                 mask <<= 24;
692
693                 if ((addr_in & mask) == (tt1 & mask) && (fc & fcmask[(tt1 >> 13) & 3]) == fcmatch[(tt1 >> 13) & 3])
694                 {
695                         MMULOG(("TT1 match on address %08x (TT0 = %08x, mask = %08x)\n", addr_in, tt1, mask));
696                         if ((tt1 & 4) && !m68ki_cpu.mmu_tmp_rw && !ptest)   // write protect?
697                         {
698                                         pmmu_set_buserror(addr_in);
699                         }
700
701                         return addr_in;
702                 }
703         }
704
705         if (m68ki_cpu.pmmu_enabled)
706         {
707                 uint32 root_idx = (addr_in >> 25) & 0x7f;
708                 uint32 ptr_idx = (addr_in >> 18) & 0x7f;
709                 uint32 page_idx, page;
710                 uint32 root_ptr, pointer_ptr, page_ptr;
711                 uint32 root_entry, pointer_entry, page_entry;
712
713                 // select supervisor or user root pointer
714                 if (fc & 4)
715                 {
716                         root_ptr = m68ki_cpu.mmu_srp_aptr + (root_idx<<2);
717                 }
718                 else
719                 {
720                         root_ptr = m68ki_cpu.mmu_urp_aptr + (root_idx<<2);
721                 }
722
723                 // get the root entry
724                 root_entry = m68k_read_memory_32(root_ptr);
725
726                 // is UDT marked valid?
727                 if (root_entry & 2)
728                 {
729                         // we're accessing through this root entry, so set the U bit
730                         if ((!(root_entry & 0x8)) && (!ptest) && !m_side_effects_disabled)
731                         {
732                                 root_entry |= 0x8;
733                                 m68k_write_memory_32(root_ptr, root_entry);
734                         }
735
736                         // PTEST: any write protect bits set in the search tree will set W in SR
737                         if ((ptest) && (root_entry & 4))
738                         {
739                                 m68ki_cpu.mmu_tmp_sr |= 4;
740                         }
741
742                         pointer_ptr = (root_entry & ~0x1ff) + (ptr_idx<<2);
743                         pointer_entry = m68k_read_memory_32(pointer_ptr);
744
745                         // PTEST: any write protect bits set in the search tree will set W in SR
746                         if ((ptest) && (pointer_entry & 4))
747                         {
748                                 m68ki_cpu.mmu_tmp_sr |= 4;
749                         }
750
751                         // update U bit on this pointer entry too
752                         if ((!(pointer_entry & 0x8)) && (!ptest) && !m_side_effects_disabled)
753                         {
754                                 pointer_entry |= 0x8;
755                                 m68k_write_memory_32(pointer_ptr, pointer_entry);
756                         }
757
758                         MMULOG(("pointer entry = %08x\n", pointer_entry));
759
760                         // write protected by the root or pointer entries?
761                         if ((((root_entry & 4) && !m68ki_cpu.mmu_tmp_rw) || ((pointer_entry & 4) && !m68ki_cpu.mmu_tmp_rw)) && !ptest)
762                         {
763                                 pmmu_set_buserror(addr_in);
764                                 return addr_in;
765                         }
766
767                         // is UDT valid on the pointer entry?
768                         if (!(pointer_entry & 2) && !ptest)
769                         {
770                                 logerror("Invalid pointer entry!  PC=%x, addr=%x\n", m68ki_cpu.ppc, addr_in);
771                                 pmmu_set_buserror(addr_in);
772                                 return addr_in;
773                         }
774
775                         // (fall out of these ifs into the page lookup below)
776                 }
777                 else // throw an error
778                 {
779                         logerror("Invalid root entry!  PC=%x, addr=%x\n", m68ki_cpu.ppc, addr_in);
780
781                         if (!ptest)
782                         {
783                                 pmmu_set_buserror(addr_in);
784                         }
785
786                         return addr_in;
787                 }
788
789                 // now do the page lookup
790                 if (m68ki_cpu.mmu_tc & 0x4000)  // 8k pages?
791                 {
792                         page_idx = (addr_in >> 13) & 0x1f;
793                         page = addr_in & 0x1fff;
794                         pointer_entry &= ~0x7f;
795                         MMULOG(("8k pages: index %x page %x\n", page_idx, page));
796                 }
797                 else    // 4k pages
798                 {
799                         page_idx = (addr_in >> 12) & 0x3f;
800                         page = addr_in & 0xfff;
801                         pointer_entry &= ~0xff;
802                         MMULOG(("4k pages: index %x page %x\n", page_idx, page));
803                 }
804
805                 page_ptr = pointer_entry + (page_idx<<2);
806                 page_entry = m68k_read_memory_32(page_ptr);
807                 m68ki_cpu.mmu_last_page_entry_addr = page_ptr;
808
809                 MMULOG(("page_entry = %08x\n", page_entry));
810
811                 // resolve indirect page pointers
812                 while ((page_entry & 3) == 2)
813                 {
814                         page_entry = m68k_read_memory_32(page_entry & ~0x3);
815                         m68ki_cpu.mmu_last_page_entry_addr = (page_entry & ~0x3);
816                 }
817                 m68ki_cpu.mmu_last_page_entry = page_entry;
818
819                 // is the page write protected or supervisor protected?
820                 if ((((page_entry & 4) && !m68ki_cpu.mmu_tmp_rw) || ((page_entry & 0x80) && !(fc & 4))) && !ptest)
821                 {
822                         pmmu_set_buserror(addr_in);
823                         return addr_in;
824                 }
825
826                 switch (page_entry & 3)
827                 {
828                         case 0: // invalid
829                                 MMULOG(("Invalid page entry!  PC=%x, addr=%x\n", m68ki_cpu.ppc, addr_in));
830                                 if (!ptest)
831                                 {
832                                         pmmu_set_buserror(addr_in);
833                                 }
834
835                                 return addr_in;
836
837                         case 1:
838                         case 3: // normal
839                                 if (m68ki_cpu.mmu_tc & 0x4000)  // 8k pages?
840                                 {
841                                         addr_out = (page_entry & ~0x1fff) | page;
842                                 }
843                                 else
844                                 {
845                                         addr_out = (page_entry & ~0xfff) | page;
846                                 }
847
848                                 if (!(ptest))
849                                 {
850                                         page_entry |= 0x8;  // always set the U bit
851
852                                         // if we're writing, the M bit comes into play
853                                         if (!m68ki_cpu.mmu_tmp_rw)
854                                         {
855                                                 page_entry |= 0x10; // set Modified
856                                         }
857
858                                         // if these updates resulted in a change, write the entry back where we found it
859                                         if (page_entry != m68ki_cpu.mmu_last_page_entry && !m_side_effects_disabled)
860                                         {
861                                                 m68ki_cpu.mmu_last_page_entry = page_entry;
862                                                 m68k_write_memory_32(m68ki_cpu.mmu_last_page_entry_addr, m68ki_cpu.mmu_last_page_entry);
863                                         }
864                                 }
865                                 else
866                                 {
867                                         // page entry: UR G U1 U0 S CM CM M U W PDT
868                                         // SR:         B  G U1 U0 S CM CM M 0 W T R
869                                         m68ki_cpu.mmu_tmp_sr |= ((addr_out & ~0xfff) || (page_entry & 0x7f4));
870                                 }
871                                 break;
872
873                         case 2: // shouldn't happen
874                                 fatalerror("68040: got indirect final page pointer, shouldn't be possible\n");
875                                 break;
876                 }
877                 //      if (addr_in != addr_out) MMULOG(("040MMU: [%08x] => [%08x]\n", addr_in, addr_out));
878         }
879
880         return addr_out;
881 }
882
883 // pmmu_translate_addr: perform 68851/68030-style PMMU address translation
884 uint32 pmmu_translate_addr(uint32 addr_in, uint16 rw)
885 {
886         uint32 addr_out;
887
888         if (CPU_TYPE_IS_040_PLUS(m68ki_cpu.cpu_type))
889         {
890                 addr_out = pmmu_translate_addr_with_fc_040(addr_in, m68ki_cpu.mmu_tmp_fc, 0);
891         }
892         else
893         {
894                 addr_out = pmmu_translate_addr_with_fc(addr_in, m68ki_cpu.mmu_tmp_fc, rw,7,0,0);
895                 MMULOG(("ADDRIN %08X, ADDROUT %08X\n", addr_in, addr_out));
896         }
897         return addr_out;
898 }
899
900 int fc_from_modes(uint16 modes)
901 {
902         if ((modes & 0x1f) == 0)
903         {
904                 return m68ki_cpu.sfc;
905         }
906
907         if ((modes & 0x1f) == 1)
908         {
909                 return m68ki_cpu.dfc;
910         }
911
912         if (m68ki_cpu.cpu_type & CPU_TYPE_030)
913         {
914                 // 68030 has 3 bits fc, but 68851 4 bits
915                 if (((modes >> 3) & 3) == 1)
916                 {
917                         return REG_D[modes & 7] & 0x7;
918                 }
919
920                 if (((modes >> 3) & 3) == 2)
921                 {
922                         return modes & 7;
923                 }
924         }
925         else
926         {
927                 if (((modes >> 3) & 3) == 1)
928                 {
929                         return REG_D[modes & 7] & 0xf;
930                 }
931
932                 if (modes & 0x10)
933                 {
934                         return modes & 0xf;
935                 }
936         }
937
938
939         fatalerror("%s: unknown fc mode: 0x%02xn", __func__, modes & 0x1f);
940         return 0;
941 }
942
943 void m68851_pload(uint32 ea, uint16 modes)
944 {
945         uint32 ltmp = DECODE_EA_32(ea);
946         int fc = fc_from_modes(modes);
947         uint16 rw = !!(modes & 0x200);
948
949         MMULOG(("%s: PLOAD%c addr=%08x, fc=%d\n", __func__, rw ? 'R' : 'W', ltmp, fc));
950
951         // MC68851 traps if MMU is not enabled, 030 not
952         if (m68ki_cpu.pmmu_enabled || (m68ki_cpu.cpu_type & CPU_TYPE_030))
953         {
954                 if (CPU_TYPE_IS_040_PLUS(m68ki_cpu.cpu_type))
955                 {
956                         pmmu_translate_addr_with_fc_040(ltmp, fc, 0);
957                 }
958                 else
959                 {
960                         pmmu_translate_addr_with_fc(ltmp, fc, rw , 7, 0, 1);
961                 }
962         }
963         else
964         {
965                 MMULOG(("PLOAD with MMU disabled on MC68851\n"));
966                 m68ki_exception_trap(57);
967                 return;
968         }
969 }
970
971 void m68851_ptest(uint32 ea, uint16 modes)
972 {
973         uint32 v_addr = DECODE_EA_32(ea);
974         uint32 p_addr;
975
976         int level = (modes >> 10) & 7;
977         uint16 rw = !!(modes & 0x200);
978         int fc = fc_from_modes(modes);
979
980         MMULOG(("PMMU: PTEST%c (%04X) pc=%08x sp=%08x va=%08x fc=%x level=%x a=%d, areg=%d\n",
981                         rw ? 'R' : 'W', modes, m68ki_cpu.ppc, REG_A[7], v_addr, fc, level,
982                                         (modes & 0x100) ? 1 : 0, (modes >> 5) & 7));
983
984         if (CPU_TYPE_IS_040_PLUS(m68ki_cpu.cpu_type))
985         {
986                 p_addr = pmmu_translate_addr_with_fc_040(v_addr, fc, 1);
987         }
988         else
989         {
990                 p_addr = pmmu_translate_addr_with_fc(v_addr, fc, rw, level, 1, 0);
991         }
992
993         m68ki_cpu.mmu_sr = m68ki_cpu.mmu_tmp_sr;
994
995         MMULOG(("PMMU: PTEST result: %04x pa=%08x\n", m68ki_cpu.mmu_sr, p_addr));
996         if (modes & 0x100)
997         {
998                 int areg = (modes >> 5) & 7;
999                 WRITE_EA_32(0x08 | areg, p_addr);
1000         }
1001 }
1002
1003 void m68851_pmove_get(uint32 ea, uint16 modes)
1004 {
1005         switch ((modes>>10) & 0x3f)
1006         {
1007         case 0x02: // transparent translation register 0
1008                 WRITE_EA_32(ea, m68ki_cpu.mmu_tt0);
1009                 MMULOG(("PMMU: pc=%x PMOVE from mmu_tt0=%08x\n", m68ki_cpu.ppc, m68ki_cpu.mmu_tt0));
1010                 break;
1011         case 0x03: // transparent translation register 1
1012                 WRITE_EA_32(ea, m68ki_cpu.mmu_tt1);
1013                 MMULOG(("PMMU: pc=%x PMOVE from mmu_tt1=%08x\n", m68ki_cpu.ppc, m68ki_cpu.mmu_tt1));
1014                 break;
1015         case 0x10:  // translation control register
1016                 WRITE_EA_32(ea, m68ki_cpu.mmu_tc);
1017                 MMULOG(("PMMU: pc=%x PMOVE from mmu_tc=%08x\n", m68ki_cpu.ppc, m68ki_cpu.mmu_tc));
1018                 break;
1019
1020         case 0x12: // supervisor root pointer
1021                 WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_srp_limit<<32 | (uint64)m68ki_cpu.mmu_srp_aptr);
1022                 MMULOG(("PMMU: pc=%x PMOVE from SRP limit = %08x, aptr = %08x\n", m68ki_cpu.ppc, m68ki_cpu.mmu_srp_limit, m68ki_cpu.mmu_srp_aptr));
1023                 break;
1024
1025         case 0x13: // CPU root pointer
1026                 WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_crp_limit<<32 | (uint64)m68ki_cpu.mmu_crp_aptr);
1027                 MMULOG(("PMMU: pc=%x PMOVE from CRP limit = %08x, aptr = %08x\n", m68ki_cpu.ppc, m68ki_cpu.mmu_crp_limit, m68ki_cpu.mmu_crp_aptr));
1028                 break;
1029
1030         default:
1031                 logerror("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68ki_cpu.pc);
1032                 return;
1033         }
1034
1035         if (!(modes & 0x100))   // flush ATC on moves to TC, SRP, CRP, TT with FD bit clear
1036         {
1037                 pmmu_atc_flush();
1038         }
1039
1040 }
1041
1042 void m68851_pmove_put(uint32 ea, uint16 modes)
1043 {
1044         uint64 temp64;
1045         switch ((modes>>13) & 7)
1046         {
1047         case 0:
1048         {
1049                 uint32 temp = READ_EA_32(ea);
1050
1051                 if (((modes >> 10) & 7) == 2)
1052                 {
1053                         MMULOG(("WRITE TT0 = 0x%08x\n", m68ki_cpu.mmu_tt0));
1054                         m68ki_cpu.mmu_tt0 = temp;
1055                 }
1056                 else if (((modes >> 10) & 7) == 3)
1057                 {
1058                         MMULOG(("WRITE TT1 = 0x%08x\n", m68ki_cpu.mmu_tt1));
1059                         m68ki_cpu.mmu_tt1 = temp;
1060                 }
1061                 break;
1062
1063                 // FIXME: unreachable
1064                 if (!(modes & 0x100))
1065                 {
1066                         pmmu_atc_flush();
1067                 }
1068         }
1069         /* fall through */
1070         /* no break */
1071
1072         case 1:
1073                 logerror("680x0: unknown PMOVE case 1, PC %x\n", m68ki_cpu.pc);
1074                 break;
1075
1076         case 2:
1077                 switch ((modes >> 10) & 7)
1078                 {
1079                 case 0: // translation control register
1080                         m68ki_cpu.mmu_tc = READ_EA_32(ea);
1081                         MMULOG(("PMMU: TC = %08x\n", m68ki_cpu.mmu_tc));
1082
1083                         if (m68ki_cpu.mmu_tc & 0x80000000)
1084                         {
1085                                 int bits = 0;
1086                                 for (int shift = 20; shift >= 0; shift -= 4)
1087                                 {
1088                                         bits += (m68ki_cpu.mmu_tc >> shift) & 0x0f;
1089                                 }
1090
1091                                 if (bits != 32 || !((m68ki_cpu.mmu_tc >> 23) & 1))
1092                                 {
1093                                         logerror("MMU: TC invalid!\n");
1094                                         m68ki_cpu.mmu_tc &= ~0x80000000;
1095                                         m68ki_exception_trap(EXCEPTION_MMU_CONFIGURATION);
1096                                 } else {
1097                                         m68ki_cpu.pmmu_enabled = 1;
1098                                 }
1099                                 MMULOG(("PMMU enabled\n"));
1100                         }
1101                         else
1102                         {
1103                                 m68ki_cpu.pmmu_enabled = 0;
1104                                 MMULOG(("PMMU disabled\n"));
1105                         }
1106
1107                         if (!(modes & 0x100))   // flush ATC on moves to TC, SRP, CRP with FD bit clear
1108                         {
1109                                 pmmu_atc_flush();
1110                         }
1111                         break;
1112
1113                 case 2: // supervisor root pointer
1114                         temp64 = READ_EA_64(ea);
1115                         m68ki_cpu.mmu_srp_limit = (temp64 >> 32) & 0xffffffff;
1116                         m68ki_cpu.mmu_srp_aptr = temp64 & 0xffffffff;
1117                         MMULOG(("PMMU: SRP limit = %08x aptr = %08x\n", m68ki_cpu.mmu_srp_limit, m68ki_cpu.mmu_srp_aptr));
1118                         // SRP type 0 is not allowed
1119                         if ((m68ki_cpu.mmu_srp_limit & 3) == 0)
1120                         {
1121                                 m68ki_exception_trap(EXCEPTION_MMU_CONFIGURATION);
1122                                 return;
1123                         }
1124
1125                         if (!(modes & 0x100))
1126                         {
1127                                 pmmu_atc_flush();
1128                         }
1129                         break;
1130
1131                 case 3: // CPU root pointer
1132                         temp64 = READ_EA_64(ea);
1133                         m68ki_cpu.mmu_crp_limit = (temp64 >> 32) & 0xffffffff;
1134                         m68ki_cpu.mmu_crp_aptr = temp64 & 0xffffffff;
1135                         MMULOG(("PMMU: CRP limit = %08x aptr = %08x\n", m68ki_cpu.mmu_crp_limit, m68ki_cpu.mmu_crp_aptr));
1136                         // CRP type 0 is not allowed
1137                         if ((m68ki_cpu.mmu_crp_limit & 3) == 0)
1138                         {
1139                                 m68ki_exception_trap(EXCEPTION_MMU_CONFIGURATION);
1140                                 return;
1141                         }
1142
1143                         if (!(modes & 0x100))
1144                         {
1145                                 pmmu_atc_flush();
1146                         }
1147                         break;
1148
1149                 case 7: // MC68851 Access Control Register
1150                         if (m68ki_cpu.cpu_type == CPU_TYPE_020)
1151                         {
1152                                 // DomainOS on Apollo DN3000 will only reset this to 0
1153                                 uint16 mmu_ac = READ_EA_16(ea);
1154                                 if (mmu_ac != 0)
1155                                 {
1156                                         MMULOG(("680x0 PMMU: pc=%x PMOVE to mmu_ac=%08x\n",
1157                                                         m68ki_cpu.ppc, mmu_ac));
1158                                 }
1159                                 break;
1160                         }
1161                         // fall through; unknown PMOVE mode unless MC68020 with MC68851
1162                         /* fall through */
1163                         /* no break */
1164                 default:
1165                         logerror("680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68ki_cpu.pc);
1166                         break;
1167                 }
1168                 break;
1169         case 3: // MMU status
1170         {
1171                 uint32 temp = READ_EA_32(ea);
1172                 logerror("680x0: unsupported PMOVE %x to MMU status, PC %x\n", temp, m68ki_cpu.pc);
1173         }
1174         break;
1175         }
1176 }
1177
1178
1179 void m68851_pmove(uint32 ea, uint16 modes)
1180 {
1181         switch ((modes>>13) & 0x7)
1182         {
1183         case 0: // MC68030/040 form with FD bit
1184         case 2: // MC68851 form, FD never set
1185                 if (modes & 0x200)
1186                 {
1187                         m68851_pmove_get(ea, modes);
1188                         break;
1189                 }
1190                 else    // top 3 bits of modes: 010 for this, 011 for status, 000 for transparent translation regs
1191                 {
1192                         m68851_pmove_put(ea, modes);
1193                         break;
1194                 }
1195         case 3: // MC68030 to/from status reg
1196                 if (modes & 0x200)
1197                 {
1198                         MMULOG(("%s: read SR = %04x\n", __func__, m68ki_cpu.mmu_sr));
1199                         WRITE_EA_16(ea, m68ki_cpu.mmu_sr);
1200                 }
1201                 else
1202                 {
1203                         m68ki_cpu.mmu_sr = READ_EA_16(ea);
1204                         MMULOG(("%s: write SR = %04X\n", __func__, m68ki_cpu.mmu_sr));
1205                 }
1206                 break;
1207
1208         default:
1209                 logerror("680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes >> 13) & 0x7, modes, m68ki_cpu.pc);
1210                 break;
1211
1212         }
1213
1214 }
1215
1216 void m68851_mmu_ops()
1217 {
1218         uint16 modes;
1219         uint32 ea = m68ki_cpu.ir & 0x3f;
1220
1221         // catch the 2 "weird" encodings up front (PBcc)
1222         if ((m68ki_cpu.ir & 0xffc0) == 0xf0c0)
1223         {
1224                 logerror("680x0: unhandled PBcc\n");
1225                 return;
1226         }
1227         else if ((m68ki_cpu.ir & 0xffc0) == 0xf080)
1228         {
1229                 logerror("680x0: unhandled PBcc\n");
1230                 return;
1231         }
1232         else if ((m68ki_cpu.ir & 0xffe0) == 0xf500)
1233         {
1234                 MMULOG(("68040 pflush: pc=%08x ir=%04x opmode=%d register=%d\n", REG_PC-4, m68ki_cpu.ir, (m68ki_cpu.ir >> 3) & 3, m68ki_cpu.ir & 7));
1235                 pmmu_atc_flush();
1236         }
1237         else    // the rest are 1111000xxxXXXXXX where xxx is the instruction family
1238         {
1239                 switch ((m68ki_cpu.ir>>9) & 0x7)
1240                 {
1241                         case 0:
1242                                 modes = OPER_I_16();
1243
1244                                 if ((modes & 0xfde0) == 0x2000) // PLOAD
1245                                 {
1246                                         m68851_pload(ea, modes);
1247                                         return;
1248                                 }
1249                                 else if ((modes & 0xe200) == 0x2000)    // PFLUSH
1250                                 {
1251                                         pmmu_atc_flush_fc_ea(modes);
1252                                         return;
1253                                 }
1254                                 else if (modes == 0xa000)       // PFLUSHR
1255                                 {
1256                                         pmmu_atc_flush();
1257                                         return;
1258                                 }
1259                                 else if (modes == 0x2800)       // PVALID (FORMAT 1)
1260                                 {
1261                                         logerror("680x0: unhandled PVALID1\n");
1262                                         return;
1263                                 }
1264                                 else if ((modes & 0xfff8) == 0x2c00)    // PVALID (FORMAT 2)
1265                                 {
1266                                         logerror("680x0: unhandled PVALID2\n");
1267                                         return;
1268                                 }
1269                                 else if ((modes & 0xe000) == 0x8000)    // PTEST
1270                                 {
1271                                         m68851_ptest(ea, modes);
1272                                         return;
1273                                 }
1274                                 else
1275                                 {
1276                                         m68851_pmove(ea, modes);
1277                                 }
1278                                 break;
1279
1280                         default:
1281                                 logerror("680x0: unknown PMMU instruction group %d\n", (m68ki_cpu.ir>>9) & 0x7);
1282                                 break;
1283                 }
1284         }
1285 }
1286
1287
1288 /* Apple HMMU translation is much simpler */
1289 /*
1290 inline uint32 hmmu_translate_addr(uint32 addr_in)
1291 {
1292         uint32 addr_out;
1293
1294         addr_out = addr_in;
1295
1296         // check if LC 24-bit mode is enabled - this simply blanks out A31, the V8 ignores A30-24 always
1297         if (m68ki_cpu.hmmu_enabled == M68K_HMMU_ENABLE_LC)
1298         {
1299                 addr_out = addr_in & 0xffffff;
1300         }
1301         else if (m68ki_cpu.hmmu_enabled == M68K_HMMU_ENABLE_II) // the original II does a more complex translation
1302         {
1303                 addr_out = addr_in & 0xffffff;
1304
1305                 if ((addr_out >= 0x800000) && (addr_out <= 0x8fffff))
1306                 {
1307                         addr_out |= 0x40000000; // ROM
1308                 }
1309                 else if ((addr_out >= 0x900000) && (addr_out <= 0xefffff))
1310                 {
1311                         addr_out = 0xf0000000;  // NuBus
1312                         addr_out |= ((addr_in & 0xf00000)<<4);
1313                         addr_out |= (addr_in & 0xfffff);
1314                 }
1315                 else if (addr_out >= 0xf00000)
1316                 {
1317                         addr_out |= 0x50000000; // I/O
1318                 }
1319
1320                 // (RAM is at 0 and doesn't need special massaging)
1321         }
1322
1323         return addr_out;
1324 }
1325
1326 int m68851_buserror(u32& addr)
1327 {
1328         if (!m68ki_cpu.pmmu_enabled)
1329         {
1330                 return false;
1331         }
1332
1333         if (m68ki_cpu.mmu_tablewalk)
1334         {
1335                 MMULOG(("buserror during table walk\n"));
1336                 m68ki_cpu.mmu_tmp_sr |= M68K_MMU_SR_BUS_ERROR|M68K_MMU_SR_INVALID;
1337                 return true;
1338         }
1339
1340         addr = m68ki_cpu.mmu_last_logical_addr;
1341         return false;
1342 }
1343 */