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