]> git.sesse.net Git - pistorm/blob - m68kmmu.h
first commit
[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 /*
11         pmmu_translate_addr: perform 68851/68030-style PMMU address translation
12 */
13 uint pmmu_translate_addr(uint addr_in)
14 {
15         uint32 addr_out, tbl_entry = 0, tbl_entry2, tamode = 0, tbmode = 0, tcmode = 0;
16         uint root_aptr, root_limit, tofs, is, abits, bbits, cbits;
17         uint resolved, tptr, shift;
18
19         resolved = 0;
20         addr_out = addr_in;
21
22         // if SRP is enabled and we're in supervisor mode, use it
23         if ((m68ki_cpu.mmu_tc & 0x02000000) && (m68ki_get_sr() & 0x2000))
24         {
25                 root_aptr = m68ki_cpu.mmu_srp_aptr;
26                 root_limit = m68ki_cpu.mmu_srp_limit;
27         }
28         else    // else use the CRP
29         {
30                 root_aptr = m68ki_cpu.mmu_crp_aptr;
31                 root_limit = m68ki_cpu.mmu_crp_limit;
32         }
33
34         // get initial shift (# of top bits to ignore)
35         is = (m68ki_cpu.mmu_tc>>16) & 0xf;
36         abits = (m68ki_cpu.mmu_tc>>12)&0xf;
37         bbits = (m68ki_cpu.mmu_tc>>8)&0xf;
38         cbits = (m68ki_cpu.mmu_tc>>4)&0xf;
39
40 //      fprintf(stderr,"PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68ki_cpu.mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits);
41
42         // get table A offset
43         tofs = (addr_in<<is)>>(32-abits);
44
45         // find out what format table A is
46         switch (root_limit & 3)
47         {
48                 case 0: // invalid, should cause MMU exception
49                 case 1: // page descriptor, should cause direct mapping
50                         fatalerror("680x0 PMMU: Unhandled root mode\n");
51                         break;
52
53                 case 2: // valid 4 byte descriptors
54                         tofs *= 4;
55 //                      fprintf(stderr,"PMMU: reading table A entry at %08x\n", tofs + (root_aptr & 0xfffffffc));
56                         tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc));
57                         tamode = tbl_entry & 3;
58 //                      fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
59                         break;
60
61                 case 3: // valid 8 byte descriptors
62                         tofs *= 8;
63 //                      fprintf(stderr,"PMMU: reading table A entries at %08x\n", tofs + (root_aptr & 0xfffffffc));
64                         tbl_entry2 = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc));
65                         tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc)+4);
66                         tamode = tbl_entry2 & 3;
67 //                      fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
68                         break;
69         }
70
71         // get table B offset and pointer
72         tofs = (addr_in<<(is+abits))>>(32-bbits);
73         tptr = tbl_entry & 0xfffffff0;
74
75         // find out what format table B is, if any
76         switch (tamode)
77         {
78                 case 0: // invalid, should cause MMU exception
79                         fatalerror("680x0 PMMU: Unhandled Table A mode %d (addr_in %08x)\n", tamode, addr_in);
80                         break;
81
82                 case 2: // 4-byte table B descriptor
83                         tofs *= 4;
84 //                      fprintf(stderr,"PMMU: reading table B entry at %08x\n", tofs + tptr);
85                         tbl_entry = m68k_read_memory_32( tofs + tptr);
86                         tbmode = tbl_entry & 3;
87 //                      fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
88                         break;
89
90                 case 3: // 8-byte table B descriptor
91                         tofs *= 8;
92 //                      fprintf(stderr,"PMMU: reading table B entries at %08x\n", tofs + tptr);
93                         tbl_entry2 = m68k_read_memory_32( tofs + tptr);
94                         tbl_entry = m68k_read_memory_32( tofs + tptr + 4);
95                         tbmode = tbl_entry2 & 3;
96 //                      fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
97                         break;
98
99                 case 1: // early termination descriptor
100                         tbl_entry &= 0xffffff00;
101
102                         shift = is+abits;
103                         addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
104                         resolved = 1;
105                         break;
106         }
107
108         // if table A wasn't early-out, continue to process table B
109         if (!resolved)
110         {
111                 // get table C offset and pointer
112                 tofs = (addr_in<<(is+abits+bbits))>>(32-cbits);
113                 tptr = tbl_entry & 0xfffffff0;
114
115                 switch (tbmode)
116                 {
117                         case 0: // invalid, should cause MMU exception
118                                 fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC);
119                                 break;
120
121                         case 2: // 4-byte table C descriptor
122                                 tofs *= 4;
123 //                              fprintf(stderr,"PMMU: reading table C entry at %08x\n", tofs + tptr);
124                                 tbl_entry = m68k_read_memory_32(tofs + tptr);
125                                 tcmode = tbl_entry & 3;
126 //                              fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
127                                 break;
128
129                         case 3: // 8-byte table C descriptor
130                                 tofs *= 8;
131 //                              fprintf(stderr,"PMMU: reading table C entries at %08x\n", tofs + tptr);
132                                 tbl_entry2 = m68k_read_memory_32(tofs + tptr);
133                                 tbl_entry = m68k_read_memory_32(tofs + tptr + 4);
134                                 tcmode = tbl_entry2 & 3;
135 //                              fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
136                                 break;
137
138                         case 1: // termination descriptor
139                                 tbl_entry &= 0xffffff00;
140
141                                 shift = is+abits+bbits;
142                                 addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
143                                 resolved = 1;
144                                 break;
145                 }
146         }
147
148         if (!resolved)
149         {
150                 switch (tcmode)
151                 {
152                         case 0: // invalid, should cause MMU exception
153                         case 2: // 4-byte ??? descriptor
154                         case 3: // 8-byte ??? descriptor
155                                 fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC);
156                                 break;
157
158                         case 1: // termination descriptor
159                                 tbl_entry &= 0xffffff00;
160
161                                 shift = is+abits+bbits+cbits;
162                                 addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
163                                 resolved = 1;
164                                 break;
165                 }
166         }
167
168
169 //      fprintf(stderr,"PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
170
171         return addr_out;
172 }
173
174 /*
175
176         m68881_mmu_ops: COP 0 MMU opcode handling
177
178 */
179
180 void m68881_mmu_ops()
181 {
182         uint16 modes;
183         uint32 ea = m68ki_cpu.ir & 0x3f;
184         uint64 temp64;
185
186         // catch the 2 "weird" encodings up front (PBcc)
187         if ((m68ki_cpu.ir & 0xffc0) == 0xf0c0)
188         {
189                 fprintf(stderr,"680x0: unhandled PBcc\n");
190                 return;
191         }
192         else if ((m68ki_cpu.ir & 0xffc0) == 0xf080)
193         {
194                 fprintf(stderr,"680x0: unhandled PBcc\n");
195                 return;
196         }
197         else    // the rest are 1111000xxxXXXXXX where xxx is the instruction family
198         {
199                 switch ((m68ki_cpu.ir>>9) & 0x7)
200                 {
201                         case 0:
202                                 modes = OPER_I_16();
203
204                                 if ((modes & 0xfde0) == 0x2000) // PLOAD
205                                 {
206                                         fprintf(stderr,"680x0: unhandled PLOAD\n");
207                                         return;
208                                 }
209                                 else if ((modes & 0xe200) == 0x2000)    // PFLUSH
210                                 {
211                                         fprintf(stderr,"680x0: unhandled PFLUSH PC=%x\n", REG_PC);
212                                         return;
213                                 }
214                                 else if (modes == 0xa000)       // PFLUSHR
215                                 {
216                                         fprintf(stderr,"680x0: unhandled PFLUSHR\n");
217                                         return;
218                                 }
219                                 else if (modes == 0x2800)       // PVALID (FORMAT 1)
220                                 {
221                                         fprintf(stderr,"680x0: unhandled PVALID1\n");
222                                         return;
223                                 }
224                                 else if ((modes & 0xfff8) == 0x2c00)    // PVALID (FORMAT 2)
225                                 {
226                                         fprintf(stderr,"680x0: unhandled PVALID2\n");
227                                         return;
228                                 }
229                                 else if ((modes & 0xe000) == 0x8000)    // PTEST
230                                 {
231                                         fprintf(stderr,"680x0: unhandled PTEST\n");
232                                         return;
233                                 }
234                                 else
235                                 {
236                                         switch ((modes>>13) & 0x7)
237                                         {
238                                                 case 0: // MC68030/040 form with FD bit
239                                                 case 2: // MC68881 form, FD never set
240                                                         if (modes & 0x200)
241                                                         {
242                                                                 switch ((modes>>10) & 7)
243                                                                 {
244                                                                         case 0: // translation control register
245                                                                                 WRITE_EA_32(ea, m68ki_cpu.mmu_tc);
246                                                                                 break;
247
248                                                                         case 2: // supervisor root pointer
249                                                                                 WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_srp_limit<<32 | (uint64)m68ki_cpu.mmu_srp_aptr);
250                                                                                 break;
251
252                                                                         case 3: // CPU root pointer
253                                                                                 WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_crp_limit<<32 | (uint64)m68ki_cpu.mmu_crp_aptr);
254                                                                                 break;
255
256                                                                         default:
257                                                                                 fprintf(stderr,"680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, REG_PC);
258                                                                                 break;
259                                                                 }
260                                                         }
261                                                         else
262                                                         {
263                                                                 switch ((modes>>10) & 7)
264                                                                 {
265                                                                         case 0: // translation control register
266                                                                                 m68ki_cpu.mmu_tc = READ_EA_32(ea);
267
268                                                                                 if (m68ki_cpu.mmu_tc & 0x80000000)
269                                                                                 {
270                                                                                         m68ki_cpu.pmmu_enabled = 1;
271                                                                                 }
272                                                                                 else
273                                                                                 {
274                                                                                         m68ki_cpu.pmmu_enabled = 0;
275                                                                                 }
276                                                                                 break;
277
278                                                                         case 2: // supervisor root pointer
279                                                                                 temp64 = READ_EA_64(ea);
280                                                                                 m68ki_cpu.mmu_srp_limit = (temp64>>32) & 0xffffffff;
281                                                                                 m68ki_cpu.mmu_srp_aptr = temp64 & 0xffffffff;
282                                                                                 break;
283
284                                                                         case 3: // CPU root pointer
285                                                                                 temp64 = READ_EA_64(ea);
286                                                                                 m68ki_cpu.mmu_crp_limit = (temp64>>32) & 0xffffffff;
287                                                                                 m68ki_cpu.mmu_crp_aptr = temp64 & 0xffffffff;
288                                                                                 break;
289
290                                                                         default:
291                                                                                 fprintf(stderr,"680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, REG_PC);
292                                                                                 break;
293                                                                 }
294                                                         }
295                                                         break;
296
297                                                 case 3: // MC68030 to/from status reg
298                                                         if (modes & 0x200)
299                                                         {
300                                                                 WRITE_EA_32(ea, m68ki_cpu.mmu_sr);
301                                                         }
302                                                         else
303                                                         {
304                                                                 m68ki_cpu.mmu_sr = READ_EA_32(ea);
305                                                         }
306                                                         break;
307
308                                                 default:
309                                                         fprintf(stderr,"680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, REG_PC);
310                                                         break;
311                                         }
312                                 }
313                                 break;
314
315                         default:
316                                 fprintf(stderr,"680x0: unknown PMMU instruction group %d\n", (m68ki_cpu.ir>>9) & 0x7);
317                                 break;
318                 }
319         }
320 }
321