]>
Commit | Line | Data |
---|---|---|
e6e5906b PB |
1 | /* |
2 | * m68k op helpers | |
5fafdf24 | 3 | * |
0633879f | 4 | * Copyright (c) 2006-2007 CodeSourcery |
e6e5906b PB |
5 | * Written by Paul Brook |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
8167ee88 | 18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
e6e5906b PB |
19 | */ |
20 | ||
d8416665 | 21 | #include "qemu/osdep.h" |
e6e5906b | 22 | #include "cpu.h" |
63c91552 | 23 | #include "exec/exec-all.h" |
022c62cb | 24 | #include "exec/gdbstub.h" |
e6e5906b | 25 | |
2ef6175a | 26 | #include "exec/helper-proto.h" |
24f91e81 | 27 | #include "fpu/softfloat.h" |
e1f3808e PB |
28 | |
29 | #define SIGNBIT (1u << 31) | |
30 | ||
11150915 AF |
31 | /* Sort alphabetically, except for "any". */ |
32 | static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) | |
009a4356 | 33 | { |
11150915 AF |
34 | ObjectClass *class_a = (ObjectClass *)a; |
35 | ObjectClass *class_b = (ObjectClass *)b; | |
36 | const char *name_a, *name_b; | |
37 | ||
38 | name_a = object_class_get_name(class_a); | |
39 | name_b = object_class_get_name(class_b); | |
7a9f812b | 40 | if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) { |
11150915 | 41 | return 1; |
7a9f812b | 42 | } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) { |
11150915 AF |
43 | return -1; |
44 | } else { | |
45 | return strcasecmp(name_a, name_b); | |
009a4356 LV |
46 | } |
47 | } | |
48 | ||
11150915 AF |
49 | static void m68k_cpu_list_entry(gpointer data, gpointer user_data) |
50 | { | |
51 | ObjectClass *c = data; | |
92a31361 | 52 | CPUListState *s = user_data; |
7a9f812b AF |
53 | const char *typename; |
54 | char *name; | |
11150915 | 55 | |
7a9f812b AF |
56 | typename = object_class_get_name(c); |
57 | name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU)); | |
11150915 | 58 | (*s->cpu_fprintf)(s->file, "%s\n", |
7a9f812b AF |
59 | name); |
60 | g_free(name); | |
11150915 AF |
61 | } |
62 | ||
63 | void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) | |
64 | { | |
92a31361 | 65 | CPUListState s = { |
11150915 AF |
66 | .file = f, |
67 | .cpu_fprintf = cpu_fprintf, | |
68 | }; | |
69 | GSList *list; | |
70 | ||
71 | list = object_class_get_list(TYPE_M68K_CPU, false); | |
72 | list = g_slist_sort(list, m68k_cpu_list_compare); | |
73 | g_slist_foreach(list, m68k_cpu_list_entry, &s); | |
74 | g_slist_free(list); | |
75 | } | |
76 | ||
f83311e4 | 77 | static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) |
56aebc89 PB |
78 | { |
79 | if (n < 8) { | |
f83311e4 LV |
80 | float_status s; |
81 | stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); | |
56aebc89 PB |
82 | return 8; |
83 | } | |
ba624944 LV |
84 | switch (n) { |
85 | case 8: /* fpcontrol */ | |
86 | stl_be_p(mem_buf, env->fpcr); | |
87 | return 4; | |
88 | case 9: /* fpstatus */ | |
89 | stl_be_p(mem_buf, env->fpsr); | |
90 | return 4; | |
91 | case 10: /* fpiar, not implemented */ | |
56aebc89 PB |
92 | memset(mem_buf, 0, 4); |
93 | return 4; | |
94 | } | |
95 | return 0; | |
96 | } | |
97 | ||
f83311e4 | 98 | static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) |
56aebc89 PB |
99 | { |
100 | if (n < 8) { | |
f83311e4 LV |
101 | float_status s; |
102 | env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s); | |
56aebc89 PB |
103 | return 8; |
104 | } | |
ba624944 LV |
105 | switch (n) { |
106 | case 8: /* fpcontrol */ | |
107 | cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); | |
108 | return 4; | |
109 | case 9: /* fpstatus */ | |
110 | env->fpsr = ldl_p(mem_buf); | |
111 | return 4; | |
112 | case 10: /* fpiar, not implemented */ | |
56aebc89 PB |
113 | return 4; |
114 | } | |
115 | return 0; | |
116 | } | |
117 | ||
5a4526b2 LV |
118 | static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) |
119 | { | |
120 | if (n < 8) { | |
121 | stw_be_p(mem_buf, env->fregs[n].l.upper); | |
122 | memset(mem_buf + 2, 0, 2); | |
123 | stq_be_p(mem_buf + 4, env->fregs[n].l.lower); | |
124 | return 12; | |
125 | } | |
126 | switch (n) { | |
127 | case 8: /* fpcontrol */ | |
128 | stl_be_p(mem_buf, env->fpcr); | |
129 | return 4; | |
130 | case 9: /* fpstatus */ | |
131 | stl_be_p(mem_buf, env->fpsr); | |
132 | return 4; | |
133 | case 10: /* fpiar, not implemented */ | |
134 | memset(mem_buf, 0, 4); | |
135 | return 4; | |
136 | } | |
137 | return 0; | |
138 | } | |
139 | ||
140 | static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) | |
141 | { | |
142 | if (n < 8) { | |
143 | env->fregs[n].l.upper = lduw_be_p(mem_buf); | |
144 | env->fregs[n].l.lower = ldq_be_p(mem_buf + 4); | |
145 | return 12; | |
146 | } | |
147 | switch (n) { | |
148 | case 8: /* fpcontrol */ | |
ba624944 | 149 | cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); |
5a4526b2 LV |
150 | return 4; |
151 | case 9: /* fpstatus */ | |
152 | env->fpsr = ldl_p(mem_buf); | |
153 | return 4; | |
154 | case 10: /* fpiar, not implemented */ | |
155 | return 4; | |
156 | } | |
157 | return 0; | |
158 | } | |
159 | ||
6d1bbc62 AF |
160 | void m68k_cpu_init_gdb(M68kCPU *cpu) |
161 | { | |
22169d41 | 162 | CPUState *cs = CPU(cpu); |
6d1bbc62 AF |
163 | CPUM68KState *env = &cpu->env; |
164 | ||
11150915 | 165 | if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { |
f83311e4 | 166 | gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg, |
11150915 | 167 | 11, "cf-fp.xml", 18); |
5a4526b2 LV |
168 | } else if (m68k_feature(env, M68K_FEATURE_FPU)) { |
169 | gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg, | |
170 | m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18); | |
aaed909a | 171 | } |
11150915 | 172 | /* TODO: Add [E]MAC registers. */ |
aaed909a | 173 | } |
0402f767 | 174 | |
6e22b28e | 175 | void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) |
0633879f | 176 | { |
a47dddd7 AF |
177 | M68kCPU *cpu = m68k_env_get_cpu(env); |
178 | ||
0633879f | 179 | switch (reg) { |
6e22b28e | 180 | case M68K_CR_CACR: |
20dcee94 PB |
181 | env->cacr = val; |
182 | m68k_switch_sp(env); | |
183 | break; | |
6e22b28e LV |
184 | case M68K_CR_ACR0: |
185 | case M68K_CR_ACR1: | |
186 | case M68K_CR_ACR2: | |
187 | case M68K_CR_ACR3: | |
20dcee94 | 188 | /* TODO: Implement Access Control Registers. */ |
0633879f | 189 | break; |
6e22b28e | 190 | case M68K_CR_VBR: |
0633879f PB |
191 | env->vbr = val; |
192 | break; | |
193 | /* TODO: Implement control registers. */ | |
194 | default: | |
6e22b28e LV |
195 | cpu_abort(CPU(cpu), |
196 | "Unimplemented control register write 0x%x = 0x%x\n", | |
0633879f PB |
197 | reg, val); |
198 | } | |
199 | } | |
200 | ||
6e22b28e LV |
201 | void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) |
202 | { | |
203 | M68kCPU *cpu = m68k_env_get_cpu(env); | |
204 | ||
205 | switch (reg) { | |
206 | /* MC680[1234]0 */ | |
5fa9f1f2 LV |
207 | case M68K_CR_SFC: |
208 | env->sfc = val & 7; | |
209 | return; | |
210 | case M68K_CR_DFC: | |
211 | env->dfc = val & 7; | |
212 | return; | |
6e22b28e LV |
213 | case M68K_CR_VBR: |
214 | env->vbr = val; | |
215 | return; | |
216 | /* MC680[234]0 */ | |
217 | case M68K_CR_CACR: | |
218 | env->cacr = val; | |
219 | m68k_switch_sp(env); | |
220 | return; | |
221 | /* MC680[34]0 */ | |
88b2fef6 LV |
222 | case M68K_CR_TC: |
223 | env->mmu.tcr = val; | |
224 | return; | |
e55886c3 LV |
225 | case M68K_CR_MMUSR: |
226 | env->mmu.mmusr = val; | |
227 | return; | |
88b2fef6 LV |
228 | case M68K_CR_SRP: |
229 | env->mmu.srp = val; | |
230 | return; | |
231 | case M68K_CR_URP: | |
232 | env->mmu.urp = val; | |
233 | return; | |
6e22b28e LV |
234 | case M68K_CR_USP: |
235 | env->sp[M68K_USP] = val; | |
236 | return; | |
237 | case M68K_CR_MSP: | |
238 | env->sp[M68K_SSP] = val; | |
239 | return; | |
240 | case M68K_CR_ISP: | |
241 | env->sp[M68K_ISP] = val; | |
242 | return; | |
c05c73b0 LV |
243 | /* MC68040/MC68LC040 */ |
244 | case M68K_CR_ITT0: | |
245 | env->mmu.ttr[M68K_ITTR0] = val; | |
246 | return; | |
247 | case M68K_CR_ITT1: | |
248 | env->mmu.ttr[M68K_ITTR1] = val; | |
249 | return; | |
250 | case M68K_CR_DTT0: | |
251 | env->mmu.ttr[M68K_DTTR0] = val; | |
252 | return; | |
253 | case M68K_CR_DTT1: | |
254 | env->mmu.ttr[M68K_DTTR1] = val; | |
255 | return; | |
6e22b28e LV |
256 | } |
257 | cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", | |
258 | reg, val); | |
259 | } | |
260 | ||
261 | uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) | |
262 | { | |
263 | M68kCPU *cpu = m68k_env_get_cpu(env); | |
264 | ||
265 | switch (reg) { | |
266 | /* MC680[1234]0 */ | |
5fa9f1f2 LV |
267 | case M68K_CR_SFC: |
268 | return env->sfc; | |
269 | case M68K_CR_DFC: | |
270 | return env->dfc; | |
6e22b28e LV |
271 | case M68K_CR_VBR: |
272 | return env->vbr; | |
273 | /* MC680[234]0 */ | |
274 | case M68K_CR_CACR: | |
275 | return env->cacr; | |
276 | /* MC680[34]0 */ | |
88b2fef6 LV |
277 | case M68K_CR_TC: |
278 | return env->mmu.tcr; | |
e55886c3 LV |
279 | case M68K_CR_MMUSR: |
280 | return env->mmu.mmusr; | |
88b2fef6 LV |
281 | case M68K_CR_SRP: |
282 | return env->mmu.srp; | |
6e22b28e LV |
283 | case M68K_CR_USP: |
284 | return env->sp[M68K_USP]; | |
285 | case M68K_CR_MSP: | |
286 | return env->sp[M68K_SSP]; | |
287 | case M68K_CR_ISP: | |
288 | return env->sp[M68K_ISP]; | |
88b2fef6 LV |
289 | /* MC68040/MC68LC040 */ |
290 | case M68K_CR_URP: | |
291 | return env->mmu.urp; | |
c05c73b0 LV |
292 | case M68K_CR_ITT0: |
293 | return env->mmu.ttr[M68K_ITTR0]; | |
294 | case M68K_CR_ITT1: | |
295 | return env->mmu.ttr[M68K_ITTR1]; | |
296 | case M68K_CR_DTT0: | |
297 | return env->mmu.ttr[M68K_DTTR0]; | |
298 | case M68K_CR_DTT1: | |
299 | return env->mmu.ttr[M68K_DTTR1]; | |
6e22b28e LV |
300 | } |
301 | cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n", | |
302 | reg); | |
303 | } | |
304 | ||
e1f3808e | 305 | void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) |
acf930aa PB |
306 | { |
307 | uint32_t acc; | |
308 | int8_t exthigh; | |
309 | uint8_t extlow; | |
310 | uint64_t regval; | |
311 | int i; | |
312 | if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { | |
313 | for (i = 0; i < 4; i++) { | |
314 | regval = env->macc[i]; | |
315 | exthigh = regval >> 40; | |
316 | if (env->macsr & MACSR_FI) { | |
317 | acc = regval >> 8; | |
318 | extlow = regval; | |
319 | } else { | |
320 | acc = regval; | |
321 | extlow = regval >> 32; | |
322 | } | |
323 | if (env->macsr & MACSR_FI) { | |
324 | regval = (((uint64_t)acc) << 8) | extlow; | |
325 | regval |= ((int64_t)exthigh) << 40; | |
326 | } else if (env->macsr & MACSR_SU) { | |
327 | regval = acc | (((int64_t)extlow) << 32); | |
328 | regval |= ((int64_t)exthigh) << 40; | |
329 | } else { | |
330 | regval = acc | (((uint64_t)extlow) << 32); | |
331 | regval |= ((uint64_t)(uint8_t)exthigh) << 40; | |
332 | } | |
333 | env->macc[i] = regval; | |
334 | } | |
335 | } | |
336 | env->macsr = val; | |
337 | } | |
338 | ||
20dcee94 PB |
339 | void m68k_switch_sp(CPUM68KState *env) |
340 | { | |
341 | int new_sp; | |
342 | ||
343 | env->sp[env->current_sp] = env->aregs[7]; | |
6e22b28e LV |
344 | if (m68k_feature(env, M68K_FEATURE_M68000)) { |
345 | if (env->sr & SR_S) { | |
346 | if (env->sr & SR_M) { | |
347 | new_sp = M68K_SSP; | |
348 | } else { | |
349 | new_sp = M68K_ISP; | |
350 | } | |
351 | } else { | |
352 | new_sp = M68K_USP; | |
353 | } | |
354 | } else { | |
355 | new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) | |
356 | ? M68K_SSP : M68K_USP; | |
357 | } | |
20dcee94 PB |
358 | env->aregs[7] = env->sp[new_sp]; |
359 | env->current_sp = new_sp; | |
360 | } | |
361 | ||
5fafdf24 | 362 | #if defined(CONFIG_USER_ONLY) |
0633879f | 363 | |
98670d47 | 364 | int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, |
7510454e | 365 | int mmu_idx) |
0633879f | 366 | { |
7510454e AF |
367 | M68kCPU *cpu = M68K_CPU(cs); |
368 | ||
27103424 | 369 | cs->exception_index = EXCP_ACCESS; |
7510454e | 370 | cpu->env.mmu.ar = address; |
0633879f PB |
371 | return 1; |
372 | } | |
373 | ||
374 | #else | |
375 | ||
88b2fef6 LV |
376 | /* MMU: 68040 only */ |
377 | ||
2097dca6 LV |
378 | static void print_address_zone(FILE *f, fprintf_function cpu_fprintf, |
379 | uint32_t logical, uint32_t physical, | |
380 | uint32_t size, int attr) | |
381 | { | |
382 | cpu_fprintf(f, "%08x - %08x -> %08x - %08x %c ", | |
383 | logical, logical + size - 1, | |
384 | physical, physical + size - 1, | |
385 | attr & 4 ? 'W' : '-'); | |
386 | size >>= 10; | |
387 | if (size < 1024) { | |
388 | cpu_fprintf(f, "(%d KiB)\n", size); | |
389 | } else { | |
390 | size >>= 10; | |
391 | if (size < 1024) { | |
392 | cpu_fprintf(f, "(%d MiB)\n", size); | |
393 | } else { | |
394 | size >>= 10; | |
395 | cpu_fprintf(f, "(%d GiB)\n", size); | |
396 | } | |
397 | } | |
398 | } | |
399 | ||
400 | static void dump_address_map(FILE *f, fprintf_function cpu_fprintf, | |
401 | CPUM68KState *env, uint32_t root_pointer) | |
402 | { | |
403 | int i, j, k; | |
404 | int tic_size, tic_shift; | |
405 | uint32_t tib_mask; | |
406 | uint32_t tia, tib, tic; | |
407 | uint32_t logical = 0xffffffff, physical = 0xffffffff; | |
408 | uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff; | |
409 | uint32_t last_logical, last_physical; | |
410 | int32_t size; | |
411 | int last_attr = -1, attr = -1; | |
412 | M68kCPU *cpu = m68k_env_get_cpu(env); | |
413 | CPUState *cs = CPU(cpu); | |
414 | ||
415 | if (env->mmu.tcr & M68K_TCR_PAGE_8K) { | |
416 | /* 8k page */ | |
417 | tic_size = 32; | |
418 | tic_shift = 13; | |
419 | tib_mask = M68K_8K_PAGE_MASK; | |
420 | } else { | |
421 | /* 4k page */ | |
422 | tic_size = 64; | |
423 | tic_shift = 12; | |
424 | tib_mask = M68K_4K_PAGE_MASK; | |
425 | } | |
426 | for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) { | |
427 | tia = ldl_phys(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4); | |
428 | if (!M68K_UDT_VALID(tia)) { | |
429 | continue; | |
430 | } | |
431 | for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) { | |
432 | tib = ldl_phys(cs->as, M68K_POINTER_BASE(tia) + j * 4); | |
433 | if (!M68K_UDT_VALID(tib)) { | |
434 | continue; | |
435 | } | |
436 | for (k = 0; k < tic_size; k++) { | |
437 | tic = ldl_phys(cs->as, (tib & tib_mask) + k * 4); | |
438 | if (!M68K_PDT_VALID(tic)) { | |
439 | continue; | |
440 | } | |
441 | if (M68K_PDT_INDIRECT(tic)) { | |
442 | tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic)); | |
443 | } | |
444 | ||
445 | last_logical = logical; | |
446 | logical = (i << M68K_TTS_ROOT_SHIFT) | | |
447 | (j << M68K_TTS_POINTER_SHIFT) | | |
448 | (k << tic_shift); | |
449 | ||
450 | last_physical = physical; | |
451 | physical = tic & ~((1 << tic_shift) - 1); | |
452 | ||
453 | last_attr = attr; | |
454 | attr = tic & ((1 << tic_shift) - 1); | |
455 | ||
456 | if ((logical != (last_logical + (1 << tic_shift))) || | |
457 | (physical != (last_physical + (1 << tic_shift))) || | |
458 | (attr & 4) != (last_attr & 4)) { | |
459 | ||
460 | if (first_logical != 0xffffffff) { | |
461 | size = last_logical + (1 << tic_shift) - | |
462 | first_logical; | |
463 | print_address_zone(f, cpu_fprintf, first_logical, | |
464 | first_physical, size, last_attr); | |
465 | } | |
466 | first_logical = logical; | |
467 | first_physical = physical; | |
468 | } | |
469 | } | |
470 | } | |
471 | } | |
472 | if (first_logical != logical || (attr & 4) != (last_attr & 4)) { | |
473 | size = logical + (1 << tic_shift) - first_logical; | |
474 | print_address_zone(f, cpu_fprintf, first_logical, first_physical, size, | |
475 | last_attr); | |
476 | } | |
477 | } | |
478 | ||
479 | #define DUMP_CACHEFLAGS(a) \ | |
480 | switch (a & M68K_DESC_CACHEMODE) { \ | |
481 | case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \ | |
482 | cpu_fprintf(f, "T"); \ | |
483 | break; \ | |
484 | case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \ | |
485 | cpu_fprintf(f, "C"); \ | |
486 | break; \ | |
487 | case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \ | |
488 | cpu_fprintf(f, "S"); \ | |
489 | break; \ | |
490 | case M68K_DESC_CM_NCACHE: /* noncachable */ \ | |
491 | cpu_fprintf(f, "N"); \ | |
492 | break; \ | |
493 | } | |
494 | ||
495 | static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr) | |
496 | { | |
497 | if ((ttr & M68K_TTR_ENABLED) == 0) { | |
498 | cpu_fprintf(f, "disabled\n"); | |
499 | return; | |
500 | } | |
501 | cpu_fprintf(f, "Base: 0x%08x Mask: 0x%08x Control: ", | |
502 | ttr & M68K_TTR_ADDR_BASE, | |
503 | (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT); | |
504 | switch (ttr & M68K_TTR_SFIELD) { | |
505 | case M68K_TTR_SFIELD_USER: | |
506 | cpu_fprintf(f, "U"); | |
507 | break; | |
508 | case M68K_TTR_SFIELD_SUPER: | |
509 | cpu_fprintf(f, "S"); | |
510 | break; | |
511 | default: | |
512 | cpu_fprintf(f, "*"); | |
513 | break; | |
514 | } | |
515 | DUMP_CACHEFLAGS(ttr); | |
516 | if (ttr & M68K_DESC_WRITEPROT) { | |
517 | cpu_fprintf(f, "R"); | |
518 | } else { | |
519 | cpu_fprintf(f, "W"); | |
520 | } | |
521 | cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >> | |
522 | M68K_DESC_USERATTR_SHIFT); | |
523 | } | |
524 | ||
525 | void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env) | |
526 | { | |
527 | if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { | |
528 | cpu_fprintf(f, "Translation disabled\n"); | |
529 | return; | |
530 | } | |
531 | cpu_fprintf(f, "Page Size: "); | |
532 | if (env->mmu.tcr & M68K_TCR_PAGE_8K) { | |
533 | cpu_fprintf(f, "8kB\n"); | |
534 | } else { | |
535 | cpu_fprintf(f, "4kB\n"); | |
536 | } | |
537 | ||
538 | cpu_fprintf(f, "MMUSR: "); | |
539 | if (env->mmu.mmusr & M68K_MMU_B_040) { | |
540 | cpu_fprintf(f, "BUS ERROR\n"); | |
541 | } else { | |
542 | cpu_fprintf(f, "Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000); | |
543 | /* flags found on the page descriptor */ | |
544 | if (env->mmu.mmusr & M68K_MMU_G_040) { | |
545 | cpu_fprintf(f, "G"); /* Global */ | |
546 | } else { | |
547 | cpu_fprintf(f, "."); | |
548 | } | |
549 | if (env->mmu.mmusr & M68K_MMU_S_040) { | |
550 | cpu_fprintf(f, "S"); /* Supervisor */ | |
551 | } else { | |
552 | cpu_fprintf(f, "."); | |
553 | } | |
554 | if (env->mmu.mmusr & M68K_MMU_M_040) { | |
555 | cpu_fprintf(f, "M"); /* Modified */ | |
556 | } else { | |
557 | cpu_fprintf(f, "."); | |
558 | } | |
559 | if (env->mmu.mmusr & M68K_MMU_WP_040) { | |
560 | cpu_fprintf(f, "W"); /* Write protect */ | |
561 | } else { | |
562 | cpu_fprintf(f, "."); | |
563 | } | |
564 | if (env->mmu.mmusr & M68K_MMU_T_040) { | |
565 | cpu_fprintf(f, "T"); /* Transparent */ | |
566 | } else { | |
567 | cpu_fprintf(f, "."); | |
568 | } | |
569 | if (env->mmu.mmusr & M68K_MMU_R_040) { | |
570 | cpu_fprintf(f, "R"); /* Resident */ | |
571 | } else { | |
572 | cpu_fprintf(f, "."); | |
573 | } | |
574 | cpu_fprintf(f, " Cache: "); | |
575 | DUMP_CACHEFLAGS(env->mmu.mmusr); | |
576 | cpu_fprintf(f, " U: %d\n", (env->mmu.mmusr >> 8) & 3); | |
577 | cpu_fprintf(f, "\n"); | |
578 | } | |
579 | ||
580 | cpu_fprintf(f, "ITTR0: "); | |
581 | dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR0]); | |
582 | cpu_fprintf(f, "ITTR1: "); | |
583 | dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR1]); | |
584 | cpu_fprintf(f, "DTTR0: "); | |
585 | dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR0]); | |
586 | cpu_fprintf(f, "DTTR1: "); | |
587 | dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR1]); | |
588 | ||
589 | cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp); | |
590 | dump_address_map(f, cpu_fprintf, env, env->mmu.srp); | |
591 | ||
592 | cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp); | |
593 | dump_address_map(f, cpu_fprintf, env, env->mmu.urp); | |
594 | } | |
595 | ||
c05c73b0 LV |
596 | static int check_TTR(uint32_t ttr, int *prot, target_ulong addr, |
597 | int access_type) | |
598 | { | |
599 | uint32_t base, mask; | |
600 | ||
601 | /* check if transparent translation is enabled */ | |
602 | if ((ttr & M68K_TTR_ENABLED) == 0) { | |
603 | return 0; | |
604 | } | |
605 | ||
606 | /* check mode access */ | |
607 | switch (ttr & M68K_TTR_SFIELD) { | |
608 | case M68K_TTR_SFIELD_USER: | |
609 | /* match only if user */ | |
610 | if ((access_type & ACCESS_SUPER) != 0) { | |
611 | return 0; | |
612 | } | |
613 | break; | |
614 | case M68K_TTR_SFIELD_SUPER: | |
615 | /* match only if supervisor */ | |
616 | if ((access_type & ACCESS_SUPER) == 0) { | |
617 | return 0; | |
618 | } | |
619 | break; | |
620 | default: | |
621 | /* all other values disable mode matching (FC2) */ | |
622 | break; | |
623 | } | |
624 | ||
625 | /* check address matching */ | |
626 | ||
627 | base = ttr & M68K_TTR_ADDR_BASE; | |
628 | mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK; | |
629 | mask <<= M68K_TTR_ADDR_MASK_SHIFT; | |
630 | ||
631 | if ((addr & mask) != (base & mask)) { | |
632 | return 0; | |
633 | } | |
634 | ||
635 | *prot = PAGE_READ | PAGE_EXEC; | |
636 | if ((ttr & M68K_DESC_WRITEPROT) == 0) { | |
637 | *prot |= PAGE_WRITE; | |
638 | } | |
639 | ||
640 | return 1; | |
641 | } | |
642 | ||
88b2fef6 LV |
643 | static int get_physical_address(CPUM68KState *env, hwaddr *physical, |
644 | int *prot, target_ulong address, | |
645 | int access_type, target_ulong *page_size) | |
646 | { | |
647 | M68kCPU *cpu = m68k_env_get_cpu(env); | |
648 | CPUState *cs = CPU(cpu); | |
649 | uint32_t entry; | |
650 | uint32_t next; | |
651 | target_ulong page_mask; | |
652 | bool debug = access_type & ACCESS_DEBUG; | |
653 | int page_bits; | |
c05c73b0 LV |
654 | int i; |
655 | ||
656 | /* Transparent Translation (physical = logical) */ | |
657 | for (i = 0; i < M68K_MAX_TTR; i++) { | |
658 | if (check_TTR(env->mmu.TTR(access_type, i), | |
659 | prot, address, access_type)) { | |
e55886c3 LV |
660 | if (access_type & ACCESS_PTEST) { |
661 | /* Transparent Translation Register bit */ | |
662 | env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040; | |
663 | } | |
c05c73b0 LV |
664 | *physical = address & TARGET_PAGE_MASK; |
665 | *page_size = TARGET_PAGE_SIZE; | |
666 | return 0; | |
667 | } | |
668 | } | |
88b2fef6 LV |
669 | |
670 | /* Page Table Root Pointer */ | |
671 | *prot = PAGE_READ | PAGE_WRITE; | |
672 | if (access_type & ACCESS_CODE) { | |
673 | *prot |= PAGE_EXEC; | |
674 | } | |
675 | if (access_type & ACCESS_SUPER) { | |
676 | next = env->mmu.srp; | |
677 | } else { | |
678 | next = env->mmu.urp; | |
679 | } | |
680 | ||
681 | /* Root Index */ | |
682 | entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address); | |
683 | ||
684 | next = ldl_phys(cs->as, entry); | |
685 | if (!M68K_UDT_VALID(next)) { | |
686 | return -1; | |
687 | } | |
688 | if (!(next & M68K_DESC_USED) && !debug) { | |
689 | stl_phys(cs->as, entry, next | M68K_DESC_USED); | |
690 | } | |
691 | if (next & M68K_DESC_WRITEPROT) { | |
e55886c3 LV |
692 | if (access_type & ACCESS_PTEST) { |
693 | env->mmu.mmusr |= M68K_MMU_WP_040; | |
694 | } | |
88b2fef6 LV |
695 | *prot &= ~PAGE_WRITE; |
696 | if (access_type & ACCESS_STORE) { | |
697 | return -1; | |
698 | } | |
699 | } | |
700 | ||
701 | /* Pointer Index */ | |
702 | entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address); | |
703 | ||
704 | next = ldl_phys(cs->as, entry); | |
705 | if (!M68K_UDT_VALID(next)) { | |
706 | return -1; | |
707 | } | |
708 | if (!(next & M68K_DESC_USED) && !debug) { | |
709 | stl_phys(cs->as, entry, next | M68K_DESC_USED); | |
710 | } | |
711 | if (next & M68K_DESC_WRITEPROT) { | |
e55886c3 LV |
712 | if (access_type & ACCESS_PTEST) { |
713 | env->mmu.mmusr |= M68K_MMU_WP_040; | |
714 | } | |
88b2fef6 LV |
715 | *prot &= ~PAGE_WRITE; |
716 | if (access_type & ACCESS_STORE) { | |
717 | return -1; | |
718 | } | |
719 | } | |
720 | ||
721 | /* Page Index */ | |
722 | if (env->mmu.tcr & M68K_TCR_PAGE_8K) { | |
723 | entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address); | |
724 | } else { | |
725 | entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address); | |
726 | } | |
727 | ||
728 | next = ldl_phys(cs->as, entry); | |
729 | ||
730 | if (!M68K_PDT_VALID(next)) { | |
731 | return -1; | |
732 | } | |
733 | if (M68K_PDT_INDIRECT(next)) { | |
734 | next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next)); | |
735 | } | |
736 | if (access_type & ACCESS_STORE) { | |
737 | if (next & M68K_DESC_WRITEPROT) { | |
738 | if (!(next & M68K_DESC_USED) && !debug) { | |
739 | stl_phys(cs->as, entry, next | M68K_DESC_USED); | |
740 | } | |
741 | } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) != | |
742 | (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) { | |
743 | stl_phys(cs->as, entry, | |
744 | next | (M68K_DESC_MODIFIED | M68K_DESC_USED)); | |
745 | } | |
746 | } else { | |
747 | if (!(next & M68K_DESC_USED) && !debug) { | |
748 | stl_phys(cs->as, entry, next | M68K_DESC_USED); | |
749 | } | |
750 | } | |
751 | ||
752 | if (env->mmu.tcr & M68K_TCR_PAGE_8K) { | |
753 | page_bits = 13; | |
754 | } else { | |
755 | page_bits = 12; | |
756 | } | |
757 | *page_size = 1 << page_bits; | |
758 | page_mask = ~(*page_size - 1); | |
759 | *physical = next & page_mask; | |
760 | ||
e55886c3 LV |
761 | if (access_type & ACCESS_PTEST) { |
762 | env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040; | |
763 | env->mmu.mmusr |= *physical & 0xfffff000; | |
764 | env->mmu.mmusr |= M68K_MMU_R_040; | |
765 | } | |
766 | ||
88b2fef6 LV |
767 | if (next & M68K_DESC_WRITEPROT) { |
768 | *prot &= ~PAGE_WRITE; | |
769 | if (access_type & ACCESS_STORE) { | |
770 | return -1; | |
771 | } | |
772 | } | |
773 | if (next & M68K_DESC_SUPERONLY) { | |
774 | if ((access_type & ACCESS_SUPER) == 0) { | |
775 | return -1; | |
776 | } | |
777 | } | |
778 | ||
779 | return 0; | |
780 | } | |
4fcc562b | 781 | |
00b941e5 | 782 | hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) |
4fcc562b | 783 | { |
88b2fef6 LV |
784 | M68kCPU *cpu = M68K_CPU(cs); |
785 | CPUM68KState *env = &cpu->env; | |
786 | hwaddr phys_addr; | |
787 | int prot; | |
788 | int access_type; | |
789 | target_ulong page_size; | |
790 | ||
791 | if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { | |
792 | /* MMU disabled */ | |
793 | return addr; | |
794 | } | |
795 | ||
796 | access_type = ACCESS_DATA | ACCESS_DEBUG; | |
797 | if (env->sr & SR_S) { | |
798 | access_type |= ACCESS_SUPER; | |
799 | } | |
800 | if (get_physical_address(env, &phys_addr, &prot, | |
801 | addr, access_type, &page_size) != 0) { | |
802 | return -1; | |
803 | } | |
804 | return phys_addr; | |
4fcc562b PB |
805 | } |
806 | ||
98670d47 | 807 | int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, |
7510454e | 808 | int mmu_idx) |
0633879f | 809 | { |
88b2fef6 LV |
810 | M68kCPU *cpu = M68K_CPU(cs); |
811 | CPUM68KState *env = &cpu->env; | |
812 | hwaddr physical; | |
0633879f | 813 | int prot; |
88b2fef6 LV |
814 | int access_type; |
815 | int ret; | |
816 | target_ulong page_size; | |
817 | ||
818 | if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) { | |
819 | /* MMU disabled */ | |
820 | tlb_set_page(cs, address & TARGET_PAGE_MASK, | |
821 | address & TARGET_PAGE_MASK, | |
822 | PAGE_READ | PAGE_WRITE | PAGE_EXEC, | |
823 | mmu_idx, TARGET_PAGE_SIZE); | |
824 | return 0; | |
825 | } | |
0633879f | 826 | |
88b2fef6 LV |
827 | if (rw == 2) { |
828 | access_type = ACCESS_CODE; | |
829 | rw = 0; | |
830 | } else { | |
831 | access_type = ACCESS_DATA; | |
832 | if (rw) { | |
833 | access_type |= ACCESS_STORE; | |
834 | } | |
835 | } | |
836 | ||
837 | if (mmu_idx != MMU_USER_IDX) { | |
838 | access_type |= ACCESS_SUPER; | |
839 | } | |
840 | ||
841 | ret = get_physical_address(&cpu->env, &physical, &prot, | |
842 | address, access_type, &page_size); | |
843 | if (ret == 0) { | |
844 | address &= TARGET_PAGE_MASK; | |
845 | physical += address & (page_size - 1); | |
846 | tlb_set_page(cs, address, physical, | |
847 | prot, mmu_idx, TARGET_PAGE_SIZE); | |
848 | return 0; | |
849 | } | |
850 | /* page fault */ | |
851 | env->mmu.ssw = M68K_ATC_040; | |
852 | switch (size) { | |
853 | case 1: | |
854 | env->mmu.ssw |= M68K_BA_SIZE_BYTE; | |
855 | break; | |
856 | case 2: | |
857 | env->mmu.ssw |= M68K_BA_SIZE_WORD; | |
858 | break; | |
859 | case 4: | |
860 | env->mmu.ssw |= M68K_BA_SIZE_LONG; | |
861 | break; | |
862 | } | |
863 | if (access_type & ACCESS_SUPER) { | |
864 | env->mmu.ssw |= M68K_TM_040_SUPER; | |
865 | } | |
866 | if (access_type & ACCESS_CODE) { | |
867 | env->mmu.ssw |= M68K_TM_040_CODE; | |
868 | } else { | |
869 | env->mmu.ssw |= M68K_TM_040_DATA; | |
870 | } | |
871 | if (!(access_type & ACCESS_STORE)) { | |
872 | env->mmu.ssw |= M68K_RW_040; | |
873 | } | |
874 | env->mmu.ar = address; | |
875 | cs->exception_index = EXCP_ACCESS; | |
876 | return 1; | |
0633879f PB |
877 | } |
878 | ||
879 | /* Notify CPU of a pending interrupt. Prioritization and vectoring should | |
880 | be handled by the interrupt controller. Real hardware only requests | |
881 | the vector when the interrupt is acknowledged by the CPU. For | |
882 | simplicitly we calculate it when the interrupt is signalled. */ | |
cb3fb38e | 883 | void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) |
0633879f | 884 | { |
d8ed887b | 885 | CPUState *cs = CPU(cpu); |
cb3fb38e AF |
886 | CPUM68KState *env = &cpu->env; |
887 | ||
0633879f PB |
888 | env->pending_level = level; |
889 | env->pending_vector = vector; | |
d8ed887b | 890 | if (level) { |
c3affe56 | 891 | cpu_interrupt(cs, CPU_INTERRUPT_HARD); |
d8ed887b AF |
892 | } else { |
893 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); | |
894 | } | |
0633879f PB |
895 | } |
896 | ||
897 | #endif | |
e1f3808e PB |
898 | |
899 | uint32_t HELPER(bitrev)(uint32_t x) | |
900 | { | |
901 | x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); | |
902 | x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); | |
903 | x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); | |
904 | return bswap32(x); | |
905 | } | |
906 | ||
907 | uint32_t HELPER(ff1)(uint32_t x) | |
908 | { | |
909 | int n; | |
910 | for (n = 32; x; n--) | |
911 | x >>= 1; | |
912 | return n; | |
913 | } | |
914 | ||
620c6cf6 | 915 | uint32_t HELPER(sats)(uint32_t val, uint32_t v) |
e1f3808e PB |
916 | { |
917 | /* The result has the opposite sign to the original value. */ | |
620c6cf6 | 918 | if ((int32_t)v < 0) { |
e1f3808e | 919 | val = (((int32_t)val) >> 31) ^ SIGNBIT; |
620c6cf6 | 920 | } |
e1f3808e PB |
921 | return val; |
922 | } | |
923 | ||
d2f8fb8e | 924 | void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) |
e1f3808e | 925 | { |
d2f8fb8e LV |
926 | env->sr = sr & 0xffe0; |
927 | cpu_m68k_set_ccr(env, sr); | |
e1f3808e PB |
928 | m68k_switch_sp(env); |
929 | } | |
930 | ||
d2f8fb8e LV |
931 | void HELPER(set_sr)(CPUM68KState *env, uint32_t val) |
932 | { | |
933 | cpu_m68k_set_sr(env, val); | |
934 | } | |
e1f3808e PB |
935 | |
936 | /* MAC unit. */ | |
937 | /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers | |
938 | take values, others take register numbers and manipulate the contents | |
939 | in-place. */ | |
2b3e3cfe | 940 | void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) |
e1f3808e PB |
941 | { |
942 | uint32_t mask; | |
943 | env->macc[dest] = env->macc[src]; | |
944 | mask = MACSR_PAV0 << dest; | |
945 | if (env->macsr & (MACSR_PAV0 << src)) | |
946 | env->macsr |= mask; | |
947 | else | |
948 | env->macsr &= ~mask; | |
949 | } | |
950 | ||
2b3e3cfe | 951 | uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) |
e1f3808e PB |
952 | { |
953 | int64_t product; | |
954 | int64_t res; | |
955 | ||
956 | product = (uint64_t)op1 * op2; | |
957 | res = (product << 24) >> 24; | |
958 | if (res != product) { | |
959 | env->macsr |= MACSR_V; | |
960 | if (env->macsr & MACSR_OMC) { | |
961 | /* Make sure the accumulate operation overflows. */ | |
962 | if (product < 0) | |
963 | res = ~(1ll << 50); | |
964 | else | |
965 | res = 1ll << 50; | |
966 | } | |
967 | } | |
968 | return res; | |
969 | } | |
970 | ||
2b3e3cfe | 971 | uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) |
e1f3808e PB |
972 | { |
973 | uint64_t product; | |
974 | ||
975 | product = (uint64_t)op1 * op2; | |
976 | if (product & (0xffffffull << 40)) { | |
977 | env->macsr |= MACSR_V; | |
978 | if (env->macsr & MACSR_OMC) { | |
979 | /* Make sure the accumulate operation overflows. */ | |
980 | product = 1ll << 50; | |
981 | } else { | |
982 | product &= ((1ull << 40) - 1); | |
983 | } | |
984 | } | |
985 | return product; | |
986 | } | |
987 | ||
2b3e3cfe | 988 | uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) |
e1f3808e PB |
989 | { |
990 | uint64_t product; | |
991 | uint32_t remainder; | |
992 | ||
993 | product = (uint64_t)op1 * op2; | |
994 | if (env->macsr & MACSR_RT) { | |
995 | remainder = product & 0xffffff; | |
996 | product >>= 24; | |
997 | if (remainder > 0x800000) | |
998 | product++; | |
999 | else if (remainder == 0x800000) | |
1000 | product += (product & 1); | |
1001 | } else { | |
1002 | product >>= 24; | |
1003 | } | |
1004 | return product; | |
1005 | } | |
1006 | ||
2b3e3cfe | 1007 | void HELPER(macsats)(CPUM68KState *env, uint32_t acc) |
e1f3808e PB |
1008 | { |
1009 | int64_t tmp; | |
1010 | int64_t result; | |
1011 | tmp = env->macc[acc]; | |
1012 | result = ((tmp << 16) >> 16); | |
1013 | if (result != tmp) { | |
1014 | env->macsr |= MACSR_V; | |
1015 | } | |
1016 | if (env->macsr & MACSR_V) { | |
1017 | env->macsr |= MACSR_PAV0 << acc; | |
1018 | if (env->macsr & MACSR_OMC) { | |
a1c7273b | 1019 | /* The result is saturated to 32 bits, despite overflow occurring |
e1f3808e PB |
1020 | at 48 bits. Seems weird, but that's what the hardware docs |
1021 | say. */ | |
1022 | result = (result >> 63) ^ 0x7fffffff; | |
1023 | } | |
1024 | } | |
1025 | env->macc[acc] = result; | |
1026 | } | |
1027 | ||
2b3e3cfe | 1028 | void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) |
e1f3808e PB |
1029 | { |
1030 | uint64_t val; | |
1031 | ||
1032 | val = env->macc[acc]; | |
1033 | if (val & (0xffffull << 48)) { | |
1034 | env->macsr |= MACSR_V; | |
1035 | } | |
1036 | if (env->macsr & MACSR_V) { | |
1037 | env->macsr |= MACSR_PAV0 << acc; | |
1038 | if (env->macsr & MACSR_OMC) { | |
1039 | if (val > (1ull << 53)) | |
1040 | val = 0; | |
1041 | else | |
1042 | val = (1ull << 48) - 1; | |
1043 | } else { | |
1044 | val &= ((1ull << 48) - 1); | |
1045 | } | |
1046 | } | |
1047 | env->macc[acc] = val; | |
1048 | } | |
1049 | ||
2b3e3cfe | 1050 | void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) |
e1f3808e PB |
1051 | { |
1052 | int64_t sum; | |
1053 | int64_t result; | |
1054 | ||
1055 | sum = env->macc[acc]; | |
1056 | result = (sum << 16) >> 16; | |
1057 | if (result != sum) { | |
1058 | env->macsr |= MACSR_V; | |
1059 | } | |
1060 | if (env->macsr & MACSR_V) { | |
1061 | env->macsr |= MACSR_PAV0 << acc; | |
1062 | if (env->macsr & MACSR_OMC) { | |
1063 | result = (result >> 63) ^ 0x7fffffffffffll; | |
1064 | } | |
1065 | } | |
1066 | env->macc[acc] = result; | |
1067 | } | |
1068 | ||
2b3e3cfe | 1069 | void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) |
e1f3808e PB |
1070 | { |
1071 | uint64_t val; | |
1072 | val = env->macc[acc]; | |
c4162574 | 1073 | if (val == 0) { |
e1f3808e | 1074 | env->macsr |= MACSR_Z; |
c4162574 | 1075 | } else if (val & (1ull << 47)) { |
e1f3808e | 1076 | env->macsr |= MACSR_N; |
c4162574 | 1077 | } |
e1f3808e PB |
1078 | if (env->macsr & (MACSR_PAV0 << acc)) { |
1079 | env->macsr |= MACSR_V; | |
1080 | } | |
1081 | if (env->macsr & MACSR_FI) { | |
1082 | val = ((int64_t)val) >> 40; | |
1083 | if (val != 0 && val != -1) | |
1084 | env->macsr |= MACSR_EV; | |
1085 | } else if (env->macsr & MACSR_SU) { | |
1086 | val = ((int64_t)val) >> 32; | |
1087 | if (val != 0 && val != -1) | |
1088 | env->macsr |= MACSR_EV; | |
1089 | } else { | |
1090 | if ((val >> 32) != 0) | |
1091 | env->macsr |= MACSR_EV; | |
1092 | } | |
1093 | } | |
1094 | ||
db3d7945 LV |
1095 | #define EXTSIGN(val, index) ( \ |
1096 | (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ | |
1097 | ) | |
620c6cf6 RH |
1098 | |
1099 | #define COMPUTE_CCR(op, x, n, z, v, c) { \ | |
1100 | switch (op) { \ | |
1101 | case CC_OP_FLAGS: \ | |
1102 | /* Everything in place. */ \ | |
1103 | break; \ | |
db3d7945 LV |
1104 | case CC_OP_ADDB: \ |
1105 | case CC_OP_ADDW: \ | |
1106 | case CC_OP_ADDL: \ | |
620c6cf6 RH |
1107 | res = n; \ |
1108 | src2 = v; \ | |
db3d7945 | 1109 | src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ |
620c6cf6 RH |
1110 | c = x; \ |
1111 | z = n; \ | |
1112 | v = (res ^ src1) & ~(src1 ^ src2); \ | |
1113 | break; \ | |
db3d7945 LV |
1114 | case CC_OP_SUBB: \ |
1115 | case CC_OP_SUBW: \ | |
1116 | case CC_OP_SUBL: \ | |
620c6cf6 RH |
1117 | res = n; \ |
1118 | src2 = v; \ | |
db3d7945 | 1119 | src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ |
620c6cf6 RH |
1120 | c = x; \ |
1121 | z = n; \ | |
1122 | v = (res ^ src1) & (src1 ^ src2); \ | |
1123 | break; \ | |
db3d7945 LV |
1124 | case CC_OP_CMPB: \ |
1125 | case CC_OP_CMPW: \ | |
1126 | case CC_OP_CMPL: \ | |
620c6cf6 RH |
1127 | src1 = n; \ |
1128 | src2 = v; \ | |
db3d7945 | 1129 | res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ |
620c6cf6 RH |
1130 | n = res; \ |
1131 | z = res; \ | |
1132 | c = src1 < src2; \ | |
1133 | v = (res ^ src1) & (src1 ^ src2); \ | |
1134 | break; \ | |
1135 | case CC_OP_LOGIC: \ | |
1136 | c = v = 0; \ | |
1137 | z = n; \ | |
1138 | break; \ | |
1139 | default: \ | |
1140 | cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \ | |
1141 | } \ | |
1142 | } while (0) | |
1143 | ||
1144 | uint32_t cpu_m68k_get_ccr(CPUM68KState *env) | |
e1f3808e | 1145 | { |
620c6cf6 RH |
1146 | uint32_t x, c, n, z, v; |
1147 | uint32_t res, src1, src2; | |
1148 | ||
1149 | x = env->cc_x; | |
620c6cf6 RH |
1150 | n = env->cc_n; |
1151 | z = env->cc_z; | |
1152 | v = env->cc_v; | |
db3d7945 | 1153 | c = env->cc_c; |
620c6cf6 RH |
1154 | |
1155 | COMPUTE_CCR(env->cc_op, x, n, z, v, c); | |
1156 | ||
1157 | n = n >> 31; | |
620c6cf6 | 1158 | z = (z == 0); |
db3d7945 | 1159 | v = v >> 31; |
620c6cf6 RH |
1160 | |
1161 | return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; | |
1162 | } | |
1163 | ||
1164 | uint32_t HELPER(get_ccr)(CPUM68KState *env) | |
1165 | { | |
1166 | return cpu_m68k_get_ccr(env); | |
1167 | } | |
1168 | ||
1169 | void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) | |
1170 | { | |
1171 | env->cc_x = (ccr & CCF_X ? 1 : 0); | |
1172 | env->cc_n = (ccr & CCF_N ? -1 : 0); | |
1173 | env->cc_z = (ccr & CCF_Z ? 0 : 1); | |
1174 | env->cc_v = (ccr & CCF_V ? -1 : 0); | |
1175 | env->cc_c = (ccr & CCF_C ? 1 : 0); | |
1176 | env->cc_op = CC_OP_FLAGS; | |
1177 | } | |
1178 | ||
1179 | void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) | |
1180 | { | |
1181 | cpu_m68k_set_ccr(env, ccr); | |
1182 | } | |
1183 | ||
1184 | void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) | |
1185 | { | |
1186 | uint32_t res, src1, src2; | |
1187 | ||
1188 | COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); | |
1189 | env->cc_op = CC_OP_FLAGS; | |
e1f3808e PB |
1190 | } |
1191 | ||
2b3e3cfe | 1192 | uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) |
e1f3808e PB |
1193 | { |
1194 | int rem; | |
1195 | uint32_t result; | |
1196 | ||
1197 | if (env->macsr & MACSR_SU) { | |
1198 | /* 16-bit rounding. */ | |
1199 | rem = val & 0xffffff; | |
1200 | val = (val >> 24) & 0xffffu; | |
1201 | if (rem > 0x800000) | |
1202 | val++; | |
1203 | else if (rem == 0x800000) | |
1204 | val += (val & 1); | |
1205 | } else if (env->macsr & MACSR_RT) { | |
1206 | /* 32-bit rounding. */ | |
1207 | rem = val & 0xff; | |
1208 | val >>= 8; | |
1209 | if (rem > 0x80) | |
1210 | val++; | |
1211 | else if (rem == 0x80) | |
1212 | val += (val & 1); | |
1213 | } else { | |
1214 | /* No rounding. */ | |
1215 | val >>= 8; | |
1216 | } | |
1217 | if (env->macsr & MACSR_OMC) { | |
1218 | /* Saturate. */ | |
1219 | if (env->macsr & MACSR_SU) { | |
1220 | if (val != (uint16_t) val) { | |
1221 | result = ((val >> 63) ^ 0x7fff) & 0xffff; | |
1222 | } else { | |
1223 | result = val & 0xffff; | |
1224 | } | |
1225 | } else { | |
1226 | if (val != (uint32_t)val) { | |
1227 | result = ((uint32_t)(val >> 63) & 0x7fffffff); | |
1228 | } else { | |
1229 | result = (uint32_t)val; | |
1230 | } | |
1231 | } | |
1232 | } else { | |
1233 | /* No saturation. */ | |
1234 | if (env->macsr & MACSR_SU) { | |
1235 | result = val & 0xffff; | |
1236 | } else { | |
1237 | result = (uint32_t)val; | |
1238 | } | |
1239 | } | |
1240 | return result; | |
1241 | } | |
1242 | ||
1243 | uint32_t HELPER(get_macs)(uint64_t val) | |
1244 | { | |
1245 | if (val == (int32_t)val) { | |
1246 | return (int32_t)val; | |
1247 | } else { | |
1248 | return (val >> 61) ^ ~SIGNBIT; | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | uint32_t HELPER(get_macu)(uint64_t val) | |
1253 | { | |
1254 | if ((val >> 32) == 0) { | |
1255 | return (uint32_t)val; | |
1256 | } else { | |
1257 | return 0xffffffffu; | |
1258 | } | |
1259 | } | |
1260 | ||
2b3e3cfe | 1261 | uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) |
e1f3808e PB |
1262 | { |
1263 | uint32_t val; | |
1264 | val = env->macc[acc] & 0x00ff; | |
5ce747cf | 1265 | val |= (env->macc[acc] >> 32) & 0xff00; |
e1f3808e PB |
1266 | val |= (env->macc[acc + 1] << 16) & 0x00ff0000; |
1267 | val |= (env->macc[acc + 1] >> 16) & 0xff000000; | |
1268 | return val; | |
1269 | } | |
1270 | ||
2b3e3cfe | 1271 | uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) |
e1f3808e PB |
1272 | { |
1273 | uint32_t val; | |
1274 | val = (env->macc[acc] >> 32) & 0xffff; | |
1275 | val |= (env->macc[acc + 1] >> 16) & 0xffff0000; | |
1276 | return val; | |
1277 | } | |
1278 | ||
2b3e3cfe | 1279 | void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) |
e1f3808e PB |
1280 | { |
1281 | int64_t res; | |
1282 | int32_t tmp; | |
1283 | res = env->macc[acc] & 0xffffffff00ull; | |
1284 | tmp = (int16_t)(val & 0xff00); | |
1285 | res |= ((int64_t)tmp) << 32; | |
1286 | res |= val & 0xff; | |
1287 | env->macc[acc] = res; | |
1288 | res = env->macc[acc + 1] & 0xffffffff00ull; | |
1289 | tmp = (val & 0xff000000); | |
1290 | res |= ((int64_t)tmp) << 16; | |
1291 | res |= (val >> 16) & 0xff; | |
1292 | env->macc[acc + 1] = res; | |
1293 | } | |
1294 | ||
2b3e3cfe | 1295 | void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) |
e1f3808e PB |
1296 | { |
1297 | int64_t res; | |
1298 | int32_t tmp; | |
1299 | res = (uint32_t)env->macc[acc]; | |
1300 | tmp = (int16_t)val; | |
1301 | res |= ((int64_t)tmp) << 32; | |
1302 | env->macc[acc] = res; | |
1303 | res = (uint32_t)env->macc[acc + 1]; | |
1304 | tmp = val & 0xffff0000; | |
1305 | res |= (int64_t)tmp << 16; | |
1306 | env->macc[acc + 1] = res; | |
1307 | } | |
1308 | ||
2b3e3cfe | 1309 | void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) |
e1f3808e PB |
1310 | { |
1311 | uint64_t res; | |
1312 | res = (uint32_t)env->macc[acc]; | |
1313 | res |= ((uint64_t)(val & 0xffff)) << 32; | |
1314 | env->macc[acc] = res; | |
1315 | res = (uint32_t)env->macc[acc + 1]; | |
1316 | res |= (uint64_t)(val & 0xffff0000) << 16; | |
1317 | env->macc[acc + 1] = res; | |
1318 | } | |
0bdb2b3b LV |
1319 | |
1320 | #if defined(CONFIG_SOFTMMU) | |
e55886c3 LV |
1321 | void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read) |
1322 | { | |
1323 | M68kCPU *cpu = m68k_env_get_cpu(env); | |
1324 | CPUState *cs = CPU(cpu); | |
1325 | hwaddr physical; | |
1326 | int access_type; | |
1327 | int prot; | |
1328 | int ret; | |
1329 | target_ulong page_size; | |
1330 | ||
1331 | access_type = ACCESS_PTEST; | |
1332 | if (env->dfc & 4) { | |
1333 | access_type |= ACCESS_SUPER; | |
1334 | } | |
1335 | if ((env->dfc & 3) == 2) { | |
1336 | access_type |= ACCESS_CODE; | |
1337 | } | |
1338 | if (!is_read) { | |
1339 | access_type |= ACCESS_STORE; | |
1340 | } | |
1341 | ||
1342 | env->mmu.mmusr = 0; | |
1343 | env->mmu.ssw = 0; | |
1344 | ret = get_physical_address(env, &physical, &prot, addr, | |
1345 | access_type, &page_size); | |
1346 | if (ret == 0) { | |
1347 | addr &= TARGET_PAGE_MASK; | |
1348 | physical += addr & (page_size - 1); | |
1349 | tlb_set_page(cs, addr, physical, | |
1350 | prot, access_type & ACCESS_SUPER ? | |
1351 | MMU_KERNEL_IDX : MMU_USER_IDX, page_size); | |
1352 | } | |
1353 | } | |
1354 | ||
1355 | void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode) | |
1356 | { | |
1357 | M68kCPU *cpu = m68k_env_get_cpu(env); | |
1358 | ||
1359 | switch (opmode) { | |
1360 | case 0: /* Flush page entry if not global */ | |
1361 | case 1: /* Flush page entry */ | |
1362 | tlb_flush_page(CPU(cpu), addr); | |
1363 | break; | |
1364 | case 2: /* Flush all except global entries */ | |
1365 | tlb_flush(CPU(cpu)); | |
1366 | break; | |
1367 | case 3: /* Flush all entries */ | |
1368 | tlb_flush(CPU(cpu)); | |
1369 | break; | |
1370 | } | |
1371 | } | |
1372 | ||
0bdb2b3b LV |
1373 | void HELPER(reset)(CPUM68KState *env) |
1374 | { | |
1375 | /* FIXME: reset all except CPU */ | |
1376 | } | |
1377 | #endif |