memory: unify loops to sync dirty log bitmap
[qemu/ar7.git] / target / m68k / helper.c
blob20155c7801842f8036d5aeb9b0000794e7193b65
1 /*
2 * m68k op helpers
4 * Copyright (c) 2006-2007 CodeSourcery
5 * Written by Paul Brook
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.
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.
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/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/gdbstub.h"
26 #include "exec/helper-proto.h"
28 #define SIGNBIT (1u << 31)
30 /* Sort alphabetically, except for "any". */
31 static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
33 ObjectClass *class_a = (ObjectClass *)a;
34 ObjectClass *class_b = (ObjectClass *)b;
35 const char *name_a, *name_b;
37 name_a = object_class_get_name(class_a);
38 name_b = object_class_get_name(class_b);
39 if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) {
40 return 1;
41 } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) {
42 return -1;
43 } else {
44 return strcasecmp(name_a, name_b);
48 static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
50 ObjectClass *c = data;
51 CPUListState *s = user_data;
52 const char *typename;
53 char *name;
55 typename = object_class_get_name(c);
56 name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
57 (*s->cpu_fprintf)(s->file, "%s\n",
58 name);
59 g_free(name);
62 void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
64 CPUListState s = {
65 .file = f,
66 .cpu_fprintf = cpu_fprintf,
68 GSList *list;
70 list = object_class_get_list(TYPE_M68K_CPU, false);
71 list = g_slist_sort(list, m68k_cpu_list_compare);
72 g_slist_foreach(list, m68k_cpu_list_entry, &s);
73 g_slist_free(list);
76 static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
78 if (n < 8) {
79 float_status s;
80 stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
81 return 8;
83 switch (n) {
84 case 8: /* fpcontrol */
85 stl_be_p(mem_buf, env->fpcr);
86 return 4;
87 case 9: /* fpstatus */
88 stl_be_p(mem_buf, env->fpsr);
89 return 4;
90 case 10: /* fpiar, not implemented */
91 memset(mem_buf, 0, 4);
92 return 4;
94 return 0;
97 static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
99 if (n < 8) {
100 float_status s;
101 env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
102 return 8;
104 switch (n) {
105 case 8: /* fpcontrol */
106 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
107 return 4;
108 case 9: /* fpstatus */
109 env->fpsr = ldl_p(mem_buf);
110 return 4;
111 case 10: /* fpiar, not implemented */
112 return 4;
114 return 0;
117 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
119 if (n < 8) {
120 stw_be_p(mem_buf, env->fregs[n].l.upper);
121 memset(mem_buf + 2, 0, 2);
122 stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
123 return 12;
125 switch (n) {
126 case 8: /* fpcontrol */
127 stl_be_p(mem_buf, env->fpcr);
128 return 4;
129 case 9: /* fpstatus */
130 stl_be_p(mem_buf, env->fpsr);
131 return 4;
132 case 10: /* fpiar, not implemented */
133 memset(mem_buf, 0, 4);
134 return 4;
136 return 0;
139 static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
141 if (n < 8) {
142 env->fregs[n].l.upper = lduw_be_p(mem_buf);
143 env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
144 return 12;
146 switch (n) {
147 case 8: /* fpcontrol */
148 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
149 return 4;
150 case 9: /* fpstatus */
151 env->fpsr = ldl_p(mem_buf);
152 return 4;
153 case 10: /* fpiar, not implemented */
154 return 4;
156 return 0;
159 void m68k_cpu_init_gdb(M68kCPU *cpu)
161 CPUState *cs = CPU(cpu);
162 CPUM68KState *env = &cpu->env;
164 if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
165 gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
166 11, "cf-fp.xml", 18);
167 } else if (m68k_feature(env, M68K_FEATURE_FPU)) {
168 gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
169 m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
171 /* TODO: Add [E]MAC registers. */
174 void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
176 M68kCPU *cpu = m68k_env_get_cpu(env);
178 switch (reg) {
179 case M68K_CR_CACR:
180 env->cacr = val;
181 m68k_switch_sp(env);
182 break;
183 case M68K_CR_ACR0:
184 case M68K_CR_ACR1:
185 case M68K_CR_ACR2:
186 case M68K_CR_ACR3:
187 /* TODO: Implement Access Control Registers. */
188 break;
189 case M68K_CR_VBR:
190 env->vbr = val;
191 break;
192 /* TODO: Implement control registers. */
193 default:
194 cpu_abort(CPU(cpu),
195 "Unimplemented control register write 0x%x = 0x%x\n",
196 reg, val);
200 void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
202 M68kCPU *cpu = m68k_env_get_cpu(env);
204 switch (reg) {
205 /* MC680[1234]0 */
206 case M68K_CR_SFC:
207 env->sfc = val & 7;
208 return;
209 case M68K_CR_DFC:
210 env->dfc = val & 7;
211 return;
212 case M68K_CR_VBR:
213 env->vbr = val;
214 return;
215 /* MC680[234]0 */
216 case M68K_CR_CACR:
217 env->cacr = val;
218 m68k_switch_sp(env);
219 return;
220 /* MC680[34]0 */
221 case M68K_CR_TC:
222 env->mmu.tcr = val;
223 return;
224 case M68K_CR_MMUSR:
225 env->mmu.mmusr = val;
226 return;
227 case M68K_CR_SRP:
228 env->mmu.srp = val;
229 return;
230 case M68K_CR_URP:
231 env->mmu.urp = val;
232 return;
233 case M68K_CR_USP:
234 env->sp[M68K_USP] = val;
235 return;
236 case M68K_CR_MSP:
237 env->sp[M68K_SSP] = val;
238 return;
239 case M68K_CR_ISP:
240 env->sp[M68K_ISP] = val;
241 return;
242 /* MC68040/MC68LC040 */
243 case M68K_CR_ITT0:
244 env->mmu.ttr[M68K_ITTR0] = val;
245 return;
246 case M68K_CR_ITT1:
247 env->mmu.ttr[M68K_ITTR1] = val;
248 return;
249 case M68K_CR_DTT0:
250 env->mmu.ttr[M68K_DTTR0] = val;
251 return;
252 case M68K_CR_DTT1:
253 env->mmu.ttr[M68K_DTTR1] = val;
254 return;
256 cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
257 reg, val);
260 uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
262 M68kCPU *cpu = m68k_env_get_cpu(env);
264 switch (reg) {
265 /* MC680[1234]0 */
266 case M68K_CR_SFC:
267 return env->sfc;
268 case M68K_CR_DFC:
269 return env->dfc;
270 case M68K_CR_VBR:
271 return env->vbr;
272 /* MC680[234]0 */
273 case M68K_CR_CACR:
274 return env->cacr;
275 /* MC680[34]0 */
276 case M68K_CR_TC:
277 return env->mmu.tcr;
278 case M68K_CR_MMUSR:
279 return env->mmu.mmusr;
280 case M68K_CR_SRP:
281 return env->mmu.srp;
282 case M68K_CR_USP:
283 return env->sp[M68K_USP];
284 case M68K_CR_MSP:
285 return env->sp[M68K_SSP];
286 case M68K_CR_ISP:
287 return env->sp[M68K_ISP];
288 /* MC68040/MC68LC040 */
289 case M68K_CR_URP:
290 return env->mmu.urp;
291 case M68K_CR_ITT0:
292 return env->mmu.ttr[M68K_ITTR0];
293 case M68K_CR_ITT1:
294 return env->mmu.ttr[M68K_ITTR1];
295 case M68K_CR_DTT0:
296 return env->mmu.ttr[M68K_DTTR0];
297 case M68K_CR_DTT1:
298 return env->mmu.ttr[M68K_DTTR1];
300 cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n",
301 reg);
304 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
306 uint32_t acc;
307 int8_t exthigh;
308 uint8_t extlow;
309 uint64_t regval;
310 int i;
311 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
312 for (i = 0; i < 4; i++) {
313 regval = env->macc[i];
314 exthigh = regval >> 40;
315 if (env->macsr & MACSR_FI) {
316 acc = regval >> 8;
317 extlow = regval;
318 } else {
319 acc = regval;
320 extlow = regval >> 32;
322 if (env->macsr & MACSR_FI) {
323 regval = (((uint64_t)acc) << 8) | extlow;
324 regval |= ((int64_t)exthigh) << 40;
325 } else if (env->macsr & MACSR_SU) {
326 regval = acc | (((int64_t)extlow) << 32);
327 regval |= ((int64_t)exthigh) << 40;
328 } else {
329 regval = acc | (((uint64_t)extlow) << 32);
330 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
332 env->macc[i] = regval;
335 env->macsr = val;
338 void m68k_switch_sp(CPUM68KState *env)
340 int new_sp;
342 env->sp[env->current_sp] = env->aregs[7];
343 if (m68k_feature(env, M68K_FEATURE_M68000)) {
344 if (env->sr & SR_S) {
345 if (env->sr & SR_M) {
346 new_sp = M68K_SSP;
347 } else {
348 new_sp = M68K_ISP;
350 } else {
351 new_sp = M68K_USP;
353 } else {
354 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
355 ? M68K_SSP : M68K_USP;
357 env->aregs[7] = env->sp[new_sp];
358 env->current_sp = new_sp;
361 #if defined(CONFIG_USER_ONLY)
363 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
364 int mmu_idx)
366 M68kCPU *cpu = M68K_CPU(cs);
368 cs->exception_index = EXCP_ACCESS;
369 cpu->env.mmu.ar = address;
370 return 1;
373 #else
375 /* MMU: 68040 only */
377 static void print_address_zone(FILE *f, fprintf_function cpu_fprintf,
378 uint32_t logical, uint32_t physical,
379 uint32_t size, int attr)
381 cpu_fprintf(f, "%08x - %08x -> %08x - %08x %c ",
382 logical, logical + size - 1,
383 physical, physical + size - 1,
384 attr & 4 ? 'W' : '-');
385 size >>= 10;
386 if (size < 1024) {
387 cpu_fprintf(f, "(%d KiB)\n", size);
388 } else {
389 size >>= 10;
390 if (size < 1024) {
391 cpu_fprintf(f, "(%d MiB)\n", size);
392 } else {
393 size >>= 10;
394 cpu_fprintf(f, "(%d GiB)\n", size);
399 static void dump_address_map(FILE *f, fprintf_function cpu_fprintf,
400 CPUM68KState *env, uint32_t root_pointer)
402 int i, j, k;
403 int tic_size, tic_shift;
404 uint32_t tib_mask;
405 uint32_t tia, tib, tic;
406 uint32_t logical = 0xffffffff, physical = 0xffffffff;
407 uint32_t first_logical = 0xffffffff, first_physical = 0xffffffff;
408 uint32_t last_logical, last_physical;
409 int32_t size;
410 int last_attr = -1, attr = -1;
411 M68kCPU *cpu = m68k_env_get_cpu(env);
412 CPUState *cs = CPU(cpu);
414 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
415 /* 8k page */
416 tic_size = 32;
417 tic_shift = 13;
418 tib_mask = M68K_8K_PAGE_MASK;
419 } else {
420 /* 4k page */
421 tic_size = 64;
422 tic_shift = 12;
423 tib_mask = M68K_4K_PAGE_MASK;
425 for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
426 tia = ldl_phys(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4);
427 if (!M68K_UDT_VALID(tia)) {
428 continue;
430 for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
431 tib = ldl_phys(cs->as, M68K_POINTER_BASE(tia) + j * 4);
432 if (!M68K_UDT_VALID(tib)) {
433 continue;
435 for (k = 0; k < tic_size; k++) {
436 tic = ldl_phys(cs->as, (tib & tib_mask) + k * 4);
437 if (!M68K_PDT_VALID(tic)) {
438 continue;
440 if (M68K_PDT_INDIRECT(tic)) {
441 tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic));
444 last_logical = logical;
445 logical = (i << M68K_TTS_ROOT_SHIFT) |
446 (j << M68K_TTS_POINTER_SHIFT) |
447 (k << tic_shift);
449 last_physical = physical;
450 physical = tic & ~((1 << tic_shift) - 1);
452 last_attr = attr;
453 attr = tic & ((1 << tic_shift) - 1);
455 if ((logical != (last_logical + (1 << tic_shift))) ||
456 (physical != (last_physical + (1 << tic_shift))) ||
457 (attr & 4) != (last_attr & 4)) {
459 if (first_logical != 0xffffffff) {
460 size = last_logical + (1 << tic_shift) -
461 first_logical;
462 print_address_zone(f, cpu_fprintf, first_logical,
463 first_physical, size, last_attr);
465 first_logical = logical;
466 first_physical = physical;
471 if (first_logical != logical || (attr & 4) != (last_attr & 4)) {
472 size = logical + (1 << tic_shift) - first_logical;
473 print_address_zone(f, cpu_fprintf, first_logical, first_physical, size,
474 last_attr);
478 #define DUMP_CACHEFLAGS(a) \
479 switch (a & M68K_DESC_CACHEMODE) { \
480 case M68K_DESC_CM_WRTHRU: /* cachable, write-through */ \
481 cpu_fprintf(f, "T"); \
482 break; \
483 case M68K_DESC_CM_COPYBK: /* cachable, copyback */ \
484 cpu_fprintf(f, "C"); \
485 break; \
486 case M68K_DESC_CM_SERIAL: /* noncachable, serialized */ \
487 cpu_fprintf(f, "S"); \
488 break; \
489 case M68K_DESC_CM_NCACHE: /* noncachable */ \
490 cpu_fprintf(f, "N"); \
491 break; \
494 static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr)
496 if ((ttr & M68K_TTR_ENABLED) == 0) {
497 cpu_fprintf(f, "disabled\n");
498 return;
500 cpu_fprintf(f, "Base: 0x%08x Mask: 0x%08x Control: ",
501 ttr & M68K_TTR_ADDR_BASE,
502 (ttr & M68K_TTR_ADDR_MASK) << M68K_TTR_ADDR_MASK_SHIFT);
503 switch (ttr & M68K_TTR_SFIELD) {
504 case M68K_TTR_SFIELD_USER:
505 cpu_fprintf(f, "U");
506 break;
507 case M68K_TTR_SFIELD_SUPER:
508 cpu_fprintf(f, "S");
509 break;
510 default:
511 cpu_fprintf(f, "*");
512 break;
514 DUMP_CACHEFLAGS(ttr);
515 if (ttr & M68K_DESC_WRITEPROT) {
516 cpu_fprintf(f, "R");
517 } else {
518 cpu_fprintf(f, "W");
520 cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >>
521 M68K_DESC_USERATTR_SHIFT);
524 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env)
526 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
527 cpu_fprintf(f, "Translation disabled\n");
528 return;
530 cpu_fprintf(f, "Page Size: ");
531 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
532 cpu_fprintf(f, "8kB\n");
533 } else {
534 cpu_fprintf(f, "4kB\n");
537 cpu_fprintf(f, "MMUSR: ");
538 if (env->mmu.mmusr & M68K_MMU_B_040) {
539 cpu_fprintf(f, "BUS ERROR\n");
540 } else {
541 cpu_fprintf(f, "Phy=%08x Flags: ", env->mmu.mmusr & 0xfffff000);
542 /* flags found on the page descriptor */
543 if (env->mmu.mmusr & M68K_MMU_G_040) {
544 cpu_fprintf(f, "G"); /* Global */
545 } else {
546 cpu_fprintf(f, ".");
548 if (env->mmu.mmusr & M68K_MMU_S_040) {
549 cpu_fprintf(f, "S"); /* Supervisor */
550 } else {
551 cpu_fprintf(f, ".");
553 if (env->mmu.mmusr & M68K_MMU_M_040) {
554 cpu_fprintf(f, "M"); /* Modified */
555 } else {
556 cpu_fprintf(f, ".");
558 if (env->mmu.mmusr & M68K_MMU_WP_040) {
559 cpu_fprintf(f, "W"); /* Write protect */
560 } else {
561 cpu_fprintf(f, ".");
563 if (env->mmu.mmusr & M68K_MMU_T_040) {
564 cpu_fprintf(f, "T"); /* Transparent */
565 } else {
566 cpu_fprintf(f, ".");
568 if (env->mmu.mmusr & M68K_MMU_R_040) {
569 cpu_fprintf(f, "R"); /* Resident */
570 } else {
571 cpu_fprintf(f, ".");
573 cpu_fprintf(f, " Cache: ");
574 DUMP_CACHEFLAGS(env->mmu.mmusr);
575 cpu_fprintf(f, " U: %d\n", (env->mmu.mmusr >> 8) & 3);
576 cpu_fprintf(f, "\n");
579 cpu_fprintf(f, "ITTR0: ");
580 dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR0]);
581 cpu_fprintf(f, "ITTR1: ");
582 dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_ITTR1]);
583 cpu_fprintf(f, "DTTR0: ");
584 dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR0]);
585 cpu_fprintf(f, "DTTR1: ");
586 dump_ttr(f, cpu_fprintf, env->mmu.ttr[M68K_DTTR1]);
588 cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp);
589 dump_address_map(f, cpu_fprintf, env, env->mmu.srp);
591 cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp);
592 dump_address_map(f, cpu_fprintf, env, env->mmu.urp);
595 static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
596 int access_type)
598 uint32_t base, mask;
600 /* check if transparent translation is enabled */
601 if ((ttr & M68K_TTR_ENABLED) == 0) {
602 return 0;
605 /* check mode access */
606 switch (ttr & M68K_TTR_SFIELD) {
607 case M68K_TTR_SFIELD_USER:
608 /* match only if user */
609 if ((access_type & ACCESS_SUPER) != 0) {
610 return 0;
612 break;
613 case M68K_TTR_SFIELD_SUPER:
614 /* match only if supervisor */
615 if ((access_type & ACCESS_SUPER) == 0) {
616 return 0;
618 break;
619 default:
620 /* all other values disable mode matching (FC2) */
621 break;
624 /* check address matching */
626 base = ttr & M68K_TTR_ADDR_BASE;
627 mask = (ttr & M68K_TTR_ADDR_MASK) ^ M68K_TTR_ADDR_MASK;
628 mask <<= M68K_TTR_ADDR_MASK_SHIFT;
630 if ((addr & mask) != (base & mask)) {
631 return 0;
634 *prot = PAGE_READ | PAGE_EXEC;
635 if ((ttr & M68K_DESC_WRITEPROT) == 0) {
636 *prot |= PAGE_WRITE;
639 return 1;
642 static int get_physical_address(CPUM68KState *env, hwaddr *physical,
643 int *prot, target_ulong address,
644 int access_type, target_ulong *page_size)
646 M68kCPU *cpu = m68k_env_get_cpu(env);
647 CPUState *cs = CPU(cpu);
648 uint32_t entry;
649 uint32_t next;
650 target_ulong page_mask;
651 bool debug = access_type & ACCESS_DEBUG;
652 int page_bits;
653 int i;
655 /* Transparent Translation (physical = logical) */
656 for (i = 0; i < M68K_MAX_TTR; i++) {
657 if (check_TTR(env->mmu.TTR(access_type, i),
658 prot, address, access_type)) {
659 if (access_type & ACCESS_PTEST) {
660 /* Transparent Translation Register bit */
661 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
663 *physical = address & TARGET_PAGE_MASK;
664 *page_size = TARGET_PAGE_SIZE;
665 return 0;
669 /* Page Table Root Pointer */
670 *prot = PAGE_READ | PAGE_WRITE;
671 if (access_type & ACCESS_CODE) {
672 *prot |= PAGE_EXEC;
674 if (access_type & ACCESS_SUPER) {
675 next = env->mmu.srp;
676 } else {
677 next = env->mmu.urp;
680 /* Root Index */
681 entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
683 next = ldl_phys(cs->as, entry);
684 if (!M68K_UDT_VALID(next)) {
685 return -1;
687 if (!(next & M68K_DESC_USED) && !debug) {
688 stl_phys(cs->as, entry, next | M68K_DESC_USED);
690 if (next & M68K_DESC_WRITEPROT) {
691 if (access_type & ACCESS_PTEST) {
692 env->mmu.mmusr |= M68K_MMU_WP_040;
694 *prot &= ~PAGE_WRITE;
695 if (access_type & ACCESS_STORE) {
696 return -1;
700 /* Pointer Index */
701 entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
703 next = ldl_phys(cs->as, entry);
704 if (!M68K_UDT_VALID(next)) {
705 return -1;
707 if (!(next & M68K_DESC_USED) && !debug) {
708 stl_phys(cs->as, entry, next | M68K_DESC_USED);
710 if (next & M68K_DESC_WRITEPROT) {
711 if (access_type & ACCESS_PTEST) {
712 env->mmu.mmusr |= M68K_MMU_WP_040;
714 *prot &= ~PAGE_WRITE;
715 if (access_type & ACCESS_STORE) {
716 return -1;
720 /* Page Index */
721 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
722 entry = M68K_8K_PAGE_BASE(next) | M68K_8K_PAGE_INDEX(address);
723 } else {
724 entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
727 next = ldl_phys(cs->as, entry);
729 if (!M68K_PDT_VALID(next)) {
730 return -1;
732 if (M68K_PDT_INDIRECT(next)) {
733 next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next));
735 if (access_type & ACCESS_STORE) {
736 if (next & M68K_DESC_WRITEPROT) {
737 if (!(next & M68K_DESC_USED) && !debug) {
738 stl_phys(cs->as, entry, next | M68K_DESC_USED);
740 } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
741 (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
742 stl_phys(cs->as, entry,
743 next | (M68K_DESC_MODIFIED | M68K_DESC_USED));
745 } else {
746 if (!(next & M68K_DESC_USED) && !debug) {
747 stl_phys(cs->as, entry, next | M68K_DESC_USED);
751 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
752 page_bits = 13;
753 } else {
754 page_bits = 12;
756 *page_size = 1 << page_bits;
757 page_mask = ~(*page_size - 1);
758 *physical = next & page_mask;
760 if (access_type & ACCESS_PTEST) {
761 env->mmu.mmusr |= next & M68K_MMU_SR_MASK_040;
762 env->mmu.mmusr |= *physical & 0xfffff000;
763 env->mmu.mmusr |= M68K_MMU_R_040;
766 if (next & M68K_DESC_WRITEPROT) {
767 *prot &= ~PAGE_WRITE;
768 if (access_type & ACCESS_STORE) {
769 return -1;
772 if (next & M68K_DESC_SUPERONLY) {
773 if ((access_type & ACCESS_SUPER) == 0) {
774 return -1;
778 return 0;
781 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
783 M68kCPU *cpu = M68K_CPU(cs);
784 CPUM68KState *env = &cpu->env;
785 hwaddr phys_addr;
786 int prot;
787 int access_type;
788 target_ulong page_size;
790 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
791 /* MMU disabled */
792 return addr;
795 access_type = ACCESS_DATA | ACCESS_DEBUG;
796 if (env->sr & SR_S) {
797 access_type |= ACCESS_SUPER;
799 if (get_physical_address(env, &phys_addr, &prot,
800 addr, access_type, &page_size) != 0) {
801 return -1;
803 return phys_addr;
806 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
807 int mmu_idx)
809 M68kCPU *cpu = M68K_CPU(cs);
810 CPUM68KState *env = &cpu->env;
811 hwaddr physical;
812 int prot;
813 int access_type;
814 int ret;
815 target_ulong page_size;
817 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
818 /* MMU disabled */
819 tlb_set_page(cs, address & TARGET_PAGE_MASK,
820 address & TARGET_PAGE_MASK,
821 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
822 mmu_idx, TARGET_PAGE_SIZE);
823 return 0;
826 if (rw == 2) {
827 access_type = ACCESS_CODE;
828 rw = 0;
829 } else {
830 access_type = ACCESS_DATA;
831 if (rw) {
832 access_type |= ACCESS_STORE;
836 if (mmu_idx != MMU_USER_IDX) {
837 access_type |= ACCESS_SUPER;
840 ret = get_physical_address(&cpu->env, &physical, &prot,
841 address, access_type, &page_size);
842 if (ret == 0) {
843 address &= TARGET_PAGE_MASK;
844 physical += address & (page_size - 1);
845 tlb_set_page(cs, address, physical,
846 prot, mmu_idx, TARGET_PAGE_SIZE);
847 return 0;
849 /* page fault */
850 env->mmu.ssw = M68K_ATC_040;
851 switch (size) {
852 case 1:
853 env->mmu.ssw |= M68K_BA_SIZE_BYTE;
854 break;
855 case 2:
856 env->mmu.ssw |= M68K_BA_SIZE_WORD;
857 break;
858 case 4:
859 env->mmu.ssw |= M68K_BA_SIZE_LONG;
860 break;
862 if (access_type & ACCESS_SUPER) {
863 env->mmu.ssw |= M68K_TM_040_SUPER;
865 if (access_type & ACCESS_CODE) {
866 env->mmu.ssw |= M68K_TM_040_CODE;
867 } else {
868 env->mmu.ssw |= M68K_TM_040_DATA;
870 if (!(access_type & ACCESS_STORE)) {
871 env->mmu.ssw |= M68K_RW_040;
873 env->mmu.ar = address;
874 cs->exception_index = EXCP_ACCESS;
875 return 1;
878 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
879 be handled by the interrupt controller. Real hardware only requests
880 the vector when the interrupt is acknowledged by the CPU. For
881 simplicitly we calculate it when the interrupt is signalled. */
882 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
884 CPUState *cs = CPU(cpu);
885 CPUM68KState *env = &cpu->env;
887 env->pending_level = level;
888 env->pending_vector = vector;
889 if (level) {
890 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
891 } else {
892 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
896 #endif
898 uint32_t HELPER(bitrev)(uint32_t x)
900 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau);
901 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu);
902 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u);
903 return bswap32(x);
906 uint32_t HELPER(ff1)(uint32_t x)
908 int n;
909 for (n = 32; x; n--)
910 x >>= 1;
911 return n;
914 uint32_t HELPER(sats)(uint32_t val, uint32_t v)
916 /* The result has the opposite sign to the original value. */
917 if ((int32_t)v < 0) {
918 val = (((int32_t)val) >> 31) ^ SIGNBIT;
920 return val;
923 void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
925 env->sr = sr & 0xffe0;
926 cpu_m68k_set_ccr(env, sr);
927 m68k_switch_sp(env);
930 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
932 cpu_m68k_set_sr(env, val);
935 /* MAC unit. */
936 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
937 take values, others take register numbers and manipulate the contents
938 in-place. */
939 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
941 uint32_t mask;
942 env->macc[dest] = env->macc[src];
943 mask = MACSR_PAV0 << dest;
944 if (env->macsr & (MACSR_PAV0 << src))
945 env->macsr |= mask;
946 else
947 env->macsr &= ~mask;
950 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
952 int64_t product;
953 int64_t res;
955 product = (uint64_t)op1 * op2;
956 res = (product << 24) >> 24;
957 if (res != product) {
958 env->macsr |= MACSR_V;
959 if (env->macsr & MACSR_OMC) {
960 /* Make sure the accumulate operation overflows. */
961 if (product < 0)
962 res = ~(1ll << 50);
963 else
964 res = 1ll << 50;
967 return res;
970 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
972 uint64_t product;
974 product = (uint64_t)op1 * op2;
975 if (product & (0xffffffull << 40)) {
976 env->macsr |= MACSR_V;
977 if (env->macsr & MACSR_OMC) {
978 /* Make sure the accumulate operation overflows. */
979 product = 1ll << 50;
980 } else {
981 product &= ((1ull << 40) - 1);
984 return product;
987 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
989 uint64_t product;
990 uint32_t remainder;
992 product = (uint64_t)op1 * op2;
993 if (env->macsr & MACSR_RT) {
994 remainder = product & 0xffffff;
995 product >>= 24;
996 if (remainder > 0x800000)
997 product++;
998 else if (remainder == 0x800000)
999 product += (product & 1);
1000 } else {
1001 product >>= 24;
1003 return product;
1006 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
1008 int64_t tmp;
1009 int64_t result;
1010 tmp = env->macc[acc];
1011 result = ((tmp << 16) >> 16);
1012 if (result != tmp) {
1013 env->macsr |= MACSR_V;
1015 if (env->macsr & MACSR_V) {
1016 env->macsr |= MACSR_PAV0 << acc;
1017 if (env->macsr & MACSR_OMC) {
1018 /* The result is saturated to 32 bits, despite overflow occurring
1019 at 48 bits. Seems weird, but that's what the hardware docs
1020 say. */
1021 result = (result >> 63) ^ 0x7fffffff;
1024 env->macc[acc] = result;
1027 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1029 uint64_t val;
1031 val = env->macc[acc];
1032 if (val & (0xffffull << 48)) {
1033 env->macsr |= MACSR_V;
1035 if (env->macsr & MACSR_V) {
1036 env->macsr |= MACSR_PAV0 << acc;
1037 if (env->macsr & MACSR_OMC) {
1038 if (val > (1ull << 53))
1039 val = 0;
1040 else
1041 val = (1ull << 48) - 1;
1042 } else {
1043 val &= ((1ull << 48) - 1);
1046 env->macc[acc] = val;
1049 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1051 int64_t sum;
1052 int64_t result;
1054 sum = env->macc[acc];
1055 result = (sum << 16) >> 16;
1056 if (result != sum) {
1057 env->macsr |= MACSR_V;
1059 if (env->macsr & MACSR_V) {
1060 env->macsr |= MACSR_PAV0 << acc;
1061 if (env->macsr & MACSR_OMC) {
1062 result = (result >> 63) ^ 0x7fffffffffffll;
1065 env->macc[acc] = result;
1068 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1070 uint64_t val;
1071 val = env->macc[acc];
1072 if (val == 0) {
1073 env->macsr |= MACSR_Z;
1074 } else if (val & (1ull << 47)) {
1075 env->macsr |= MACSR_N;
1077 if (env->macsr & (MACSR_PAV0 << acc)) {
1078 env->macsr |= MACSR_V;
1080 if (env->macsr & MACSR_FI) {
1081 val = ((int64_t)val) >> 40;
1082 if (val != 0 && val != -1)
1083 env->macsr |= MACSR_EV;
1084 } else if (env->macsr & MACSR_SU) {
1085 val = ((int64_t)val) >> 32;
1086 if (val != 0 && val != -1)
1087 env->macsr |= MACSR_EV;
1088 } else {
1089 if ((val >> 32) != 0)
1090 env->macsr |= MACSR_EV;
1094 #define EXTSIGN(val, index) ( \
1095 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1098 #define COMPUTE_CCR(op, x, n, z, v, c) { \
1099 switch (op) { \
1100 case CC_OP_FLAGS: \
1101 /* Everything in place. */ \
1102 break; \
1103 case CC_OP_ADDB: \
1104 case CC_OP_ADDW: \
1105 case CC_OP_ADDL: \
1106 res = n; \
1107 src2 = v; \
1108 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
1109 c = x; \
1110 z = n; \
1111 v = (res ^ src1) & ~(src1 ^ src2); \
1112 break; \
1113 case CC_OP_SUBB: \
1114 case CC_OP_SUBW: \
1115 case CC_OP_SUBL: \
1116 res = n; \
1117 src2 = v; \
1118 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
1119 c = x; \
1120 z = n; \
1121 v = (res ^ src1) & (src1 ^ src2); \
1122 break; \
1123 case CC_OP_CMPB: \
1124 case CC_OP_CMPW: \
1125 case CC_OP_CMPL: \
1126 src1 = n; \
1127 src2 = v; \
1128 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
1129 n = res; \
1130 z = res; \
1131 c = src1 < src2; \
1132 v = (res ^ src1) & (src1 ^ src2); \
1133 break; \
1134 case CC_OP_LOGIC: \
1135 c = v = 0; \
1136 z = n; \
1137 break; \
1138 default: \
1139 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
1141 } while (0)
1143 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1145 uint32_t x, c, n, z, v;
1146 uint32_t res, src1, src2;
1148 x = env->cc_x;
1149 n = env->cc_n;
1150 z = env->cc_z;
1151 v = env->cc_v;
1152 c = env->cc_c;
1154 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1156 n = n >> 31;
1157 z = (z == 0);
1158 v = v >> 31;
1160 return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1163 uint32_t HELPER(get_ccr)(CPUM68KState *env)
1165 return cpu_m68k_get_ccr(env);
1168 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
1170 env->cc_x = (ccr & CCF_X ? 1 : 0);
1171 env->cc_n = (ccr & CCF_N ? -1 : 0);
1172 env->cc_z = (ccr & CCF_Z ? 0 : 1);
1173 env->cc_v = (ccr & CCF_V ? -1 : 0);
1174 env->cc_c = (ccr & CCF_C ? 1 : 0);
1175 env->cc_op = CC_OP_FLAGS;
1178 void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1180 cpu_m68k_set_ccr(env, ccr);
1183 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1185 uint32_t res, src1, src2;
1187 COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
1188 env->cc_op = CC_OP_FLAGS;
1191 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1193 int rem;
1194 uint32_t result;
1196 if (env->macsr & MACSR_SU) {
1197 /* 16-bit rounding. */
1198 rem = val & 0xffffff;
1199 val = (val >> 24) & 0xffffu;
1200 if (rem > 0x800000)
1201 val++;
1202 else if (rem == 0x800000)
1203 val += (val & 1);
1204 } else if (env->macsr & MACSR_RT) {
1205 /* 32-bit rounding. */
1206 rem = val & 0xff;
1207 val >>= 8;
1208 if (rem > 0x80)
1209 val++;
1210 else if (rem == 0x80)
1211 val += (val & 1);
1212 } else {
1213 /* No rounding. */
1214 val >>= 8;
1216 if (env->macsr & MACSR_OMC) {
1217 /* Saturate. */
1218 if (env->macsr & MACSR_SU) {
1219 if (val != (uint16_t) val) {
1220 result = ((val >> 63) ^ 0x7fff) & 0xffff;
1221 } else {
1222 result = val & 0xffff;
1224 } else {
1225 if (val != (uint32_t)val) {
1226 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1227 } else {
1228 result = (uint32_t)val;
1231 } else {
1232 /* No saturation. */
1233 if (env->macsr & MACSR_SU) {
1234 result = val & 0xffff;
1235 } else {
1236 result = (uint32_t)val;
1239 return result;
1242 uint32_t HELPER(get_macs)(uint64_t val)
1244 if (val == (int32_t)val) {
1245 return (int32_t)val;
1246 } else {
1247 return (val >> 61) ^ ~SIGNBIT;
1251 uint32_t HELPER(get_macu)(uint64_t val)
1253 if ((val >> 32) == 0) {
1254 return (uint32_t)val;
1255 } else {
1256 return 0xffffffffu;
1260 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1262 uint32_t val;
1263 val = env->macc[acc] & 0x00ff;
1264 val |= (env->macc[acc] >> 32) & 0xff00;
1265 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1266 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1267 return val;
1270 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1272 uint32_t val;
1273 val = (env->macc[acc] >> 32) & 0xffff;
1274 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1275 return val;
1278 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
1280 int64_t res;
1281 int32_t tmp;
1282 res = env->macc[acc] & 0xffffffff00ull;
1283 tmp = (int16_t)(val & 0xff00);
1284 res |= ((int64_t)tmp) << 32;
1285 res |= val & 0xff;
1286 env->macc[acc] = res;
1287 res = env->macc[acc + 1] & 0xffffffff00ull;
1288 tmp = (val & 0xff000000);
1289 res |= ((int64_t)tmp) << 16;
1290 res |= (val >> 16) & 0xff;
1291 env->macc[acc + 1] = res;
1294 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
1296 int64_t res;
1297 int32_t tmp;
1298 res = (uint32_t)env->macc[acc];
1299 tmp = (int16_t)val;
1300 res |= ((int64_t)tmp) << 32;
1301 env->macc[acc] = res;
1302 res = (uint32_t)env->macc[acc + 1];
1303 tmp = val & 0xffff0000;
1304 res |= (int64_t)tmp << 16;
1305 env->macc[acc + 1] = res;
1308 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
1310 uint64_t res;
1311 res = (uint32_t)env->macc[acc];
1312 res |= ((uint64_t)(val & 0xffff)) << 32;
1313 env->macc[acc] = res;
1314 res = (uint32_t)env->macc[acc + 1];
1315 res |= (uint64_t)(val & 0xffff0000) << 16;
1316 env->macc[acc + 1] = res;
1319 #if defined(CONFIG_SOFTMMU)
1320 void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
1322 M68kCPU *cpu = m68k_env_get_cpu(env);
1323 CPUState *cs = CPU(cpu);
1324 hwaddr physical;
1325 int access_type;
1326 int prot;
1327 int ret;
1328 target_ulong page_size;
1330 access_type = ACCESS_PTEST;
1331 if (env->dfc & 4) {
1332 access_type |= ACCESS_SUPER;
1334 if ((env->dfc & 3) == 2) {
1335 access_type |= ACCESS_CODE;
1337 if (!is_read) {
1338 access_type |= ACCESS_STORE;
1341 env->mmu.mmusr = 0;
1342 env->mmu.ssw = 0;
1343 ret = get_physical_address(env, &physical, &prot, addr,
1344 access_type, &page_size);
1345 if (ret == 0) {
1346 addr &= TARGET_PAGE_MASK;
1347 physical += addr & (page_size - 1);
1348 tlb_set_page(cs, addr, physical,
1349 prot, access_type & ACCESS_SUPER ?
1350 MMU_KERNEL_IDX : MMU_USER_IDX, page_size);
1354 void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1356 M68kCPU *cpu = m68k_env_get_cpu(env);
1358 switch (opmode) {
1359 case 0: /* Flush page entry if not global */
1360 case 1: /* Flush page entry */
1361 tlb_flush_page(CPU(cpu), addr);
1362 break;
1363 case 2: /* Flush all except global entries */
1364 tlb_flush(CPU(cpu));
1365 break;
1366 case 3: /* Flush all entries */
1367 tlb_flush(CPU(cpu));
1368 break;
1372 void HELPER(reset)(CPUM68KState *env)
1374 /* FIXME: reset all except CPU */
1376 #endif