Travis support for the acceptance tests
[qemu/ar7.git] / target / m68k / helper.c
blob917d46efcc3389b8f7cc8a9e6ff9afcf9bd923a0
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"
27 #include "fpu/softfloat.h"
29 #define SIGNBIT (1u << 31)
31 /* Sort alphabetically, except for "any". */
32 static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b)
34 ObjectClass *class_a = (ObjectClass *)a;
35 ObjectClass *class_b = (ObjectClass *)b;
36 const char *name_a, *name_b;
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);
49 static void m68k_cpu_list_entry(gpointer data, gpointer user_data)
51 ObjectClass *c = data;
52 CPUListState *s = user_data;
53 const char *typename;
54 char *name;
56 typename = object_class_get_name(c);
57 name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU));
58 (*s->cpu_fprintf)(s->file, "%s\n",
59 name);
60 g_free(name);
63 void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
65 CPUListState s = {
66 .file = f,
67 .cpu_fprintf = cpu_fprintf,
69 GSList *list;
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);
77 static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
79 if (n < 8) {
80 float_status s;
81 stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
82 return 8;
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 */
92 memset(mem_buf, 0, 4);
93 return 4;
95 return 0;
98 static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
100 if (n < 8) {
101 float_status s;
102 env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
103 return 8;
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 */
113 return 4;
115 return 0;
118 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
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;
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;
137 return 0;
140 static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
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;
147 switch (n) {
148 case 8: /* fpcontrol */
149 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
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;
157 return 0;
160 void m68k_cpu_init_gdb(M68kCPU *cpu)
162 CPUState *cs = CPU(cpu);
163 CPUM68KState *env = &cpu->env;
165 if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
166 gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
167 11, "cf-fp.xml", 18);
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);
172 /* TODO: Add [E]MAC registers. */
175 void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
177 M68kCPU *cpu = m68k_env_get_cpu(env);
179 switch (reg) {
180 case M68K_CR_CACR:
181 env->cacr = val;
182 m68k_switch_sp(env);
183 break;
184 case M68K_CR_ACR0:
185 case M68K_CR_ACR1:
186 case M68K_CR_ACR2:
187 case M68K_CR_ACR3:
188 /* TODO: Implement Access Control Registers. */
189 break;
190 case M68K_CR_VBR:
191 env->vbr = val;
192 break;
193 /* TODO: Implement control registers. */
194 default:
195 cpu_abort(CPU(cpu),
196 "Unimplemented control register write 0x%x = 0x%x\n",
197 reg, val);
201 void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
203 M68kCPU *cpu = m68k_env_get_cpu(env);
205 switch (reg) {
206 /* MC680[1234]0 */
207 case M68K_CR_SFC:
208 env->sfc = val & 7;
209 return;
210 case M68K_CR_DFC:
211 env->dfc = val & 7;
212 return;
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 */
222 case M68K_CR_TC:
223 env->mmu.tcr = val;
224 return;
225 case M68K_CR_MMUSR:
226 env->mmu.mmusr = val;
227 return;
228 case M68K_CR_SRP:
229 env->mmu.srp = val;
230 return;
231 case M68K_CR_URP:
232 env->mmu.urp = val;
233 return;
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;
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;
257 cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
258 reg, val);
261 uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
263 M68kCPU *cpu = m68k_env_get_cpu(env);
265 switch (reg) {
266 /* MC680[1234]0 */
267 case M68K_CR_SFC:
268 return env->sfc;
269 case M68K_CR_DFC:
270 return env->dfc;
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 */
277 case M68K_CR_TC:
278 return env->mmu.tcr;
279 case M68K_CR_MMUSR:
280 return env->mmu.mmusr;
281 case M68K_CR_SRP:
282 return env->mmu.srp;
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];
289 /* MC68040/MC68LC040 */
290 case M68K_CR_URP:
291 return env->mmu.urp;
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];
301 cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n",
302 reg);
305 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
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;
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;
333 env->macc[i] = regval;
336 env->macsr = val;
339 void m68k_switch_sp(CPUM68KState *env)
341 int new_sp;
343 env->sp[env->current_sp] = env->aregs[7];
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;
351 } else {
352 new_sp = M68K_USP;
354 } else {
355 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
356 ? M68K_SSP : M68K_USP;
358 env->aregs[7] = env->sp[new_sp];
359 env->current_sp = new_sp;
362 #if defined(CONFIG_USER_ONLY)
364 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
365 int mmu_idx)
367 M68kCPU *cpu = M68K_CPU(cs);
369 cs->exception_index = EXCP_ACCESS;
370 cpu->env.mmu.ar = address;
371 return 1;
374 #else
376 /* MMU: 68040 only */
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)
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);
400 static void dump_address_map(FILE *f, fprintf_function cpu_fprintf,
401 CPUM68KState *env, uint32_t root_pointer)
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);
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;
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;
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;
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;
441 if (M68K_PDT_INDIRECT(tic)) {
442 tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic));
445 last_logical = logical;
446 logical = (i << M68K_TTS_ROOT_SHIFT) |
447 (j << M68K_TTS_POINTER_SHIFT) |
448 (k << tic_shift);
450 last_physical = physical;
451 physical = tic & ~((1 << tic_shift) - 1);
453 last_attr = attr;
454 attr = tic & ((1 << tic_shift) - 1);
456 if ((logical != (last_logical + (1 << tic_shift))) ||
457 (physical != (last_physical + (1 << tic_shift))) ||
458 (attr & 4) != (last_attr & 4)) {
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);
466 first_logical = logical;
467 first_physical = physical;
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);
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; \
495 static void dump_ttr(FILE *f, fprintf_function cpu_fprintf, uint32_t ttr)
497 if ((ttr & M68K_TTR_ENABLED) == 0) {
498 cpu_fprintf(f, "disabled\n");
499 return;
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;
515 DUMP_CACHEFLAGS(ttr);
516 if (ttr & M68K_DESC_WRITEPROT) {
517 cpu_fprintf(f, "R");
518 } else {
519 cpu_fprintf(f, "W");
521 cpu_fprintf(f, " U: %d\n", (ttr & M68K_DESC_USERATTR) >>
522 M68K_DESC_USERATTR_SHIFT);
525 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUM68KState *env)
527 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
528 cpu_fprintf(f, "Translation disabled\n");
529 return;
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");
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, ".");
549 if (env->mmu.mmusr & M68K_MMU_S_040) {
550 cpu_fprintf(f, "S"); /* Supervisor */
551 } else {
552 cpu_fprintf(f, ".");
554 if (env->mmu.mmusr & M68K_MMU_M_040) {
555 cpu_fprintf(f, "M"); /* Modified */
556 } else {
557 cpu_fprintf(f, ".");
559 if (env->mmu.mmusr & M68K_MMU_WP_040) {
560 cpu_fprintf(f, "W"); /* Write protect */
561 } else {
562 cpu_fprintf(f, ".");
564 if (env->mmu.mmusr & M68K_MMU_T_040) {
565 cpu_fprintf(f, "T"); /* Transparent */
566 } else {
567 cpu_fprintf(f, ".");
569 if (env->mmu.mmusr & M68K_MMU_R_040) {
570 cpu_fprintf(f, "R"); /* Resident */
571 } else {
572 cpu_fprintf(f, ".");
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");
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]);
589 cpu_fprintf(f, "SRP: 0x%08x\n", env->mmu.srp);
590 dump_address_map(f, cpu_fprintf, env, env->mmu.srp);
592 cpu_fprintf(f, "URP: 0x%08x\n", env->mmu.urp);
593 dump_address_map(f, cpu_fprintf, env, env->mmu.urp);
596 static int check_TTR(uint32_t ttr, int *prot, target_ulong addr,
597 int access_type)
599 uint32_t base, mask;
601 /* check if transparent translation is enabled */
602 if ((ttr & M68K_TTR_ENABLED) == 0) {
603 return 0;
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;
613 break;
614 case M68K_TTR_SFIELD_SUPER:
615 /* match only if supervisor */
616 if ((access_type & ACCESS_SUPER) == 0) {
617 return 0;
619 break;
620 default:
621 /* all other values disable mode matching (FC2) */
622 break;
625 /* check address matching */
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;
631 if ((addr & mask) != (base & mask)) {
632 return 0;
635 *prot = PAGE_READ | PAGE_EXEC;
636 if ((ttr & M68K_DESC_WRITEPROT) == 0) {
637 *prot |= PAGE_WRITE;
640 return 1;
643 static int get_physical_address(CPUM68KState *env, hwaddr *physical,
644 int *prot, target_ulong address,
645 int access_type, target_ulong *page_size)
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;
654 int i;
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)) {
660 if (access_type & ACCESS_PTEST) {
661 /* Transparent Translation Register bit */
662 env->mmu.mmusr = M68K_MMU_T_040 | M68K_MMU_R_040;
664 *physical = address & TARGET_PAGE_MASK;
665 *page_size = TARGET_PAGE_SIZE;
666 return 0;
670 /* Page Table Root Pointer */
671 *prot = PAGE_READ | PAGE_WRITE;
672 if (access_type & ACCESS_CODE) {
673 *prot |= PAGE_EXEC;
675 if (access_type & ACCESS_SUPER) {
676 next = env->mmu.srp;
677 } else {
678 next = env->mmu.urp;
681 /* Root Index */
682 entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
684 next = ldl_phys(cs->as, entry);
685 if (!M68K_UDT_VALID(next)) {
686 return -1;
688 if (!(next & M68K_DESC_USED) && !debug) {
689 stl_phys(cs->as, entry, next | M68K_DESC_USED);
691 if (next & M68K_DESC_WRITEPROT) {
692 if (access_type & ACCESS_PTEST) {
693 env->mmu.mmusr |= M68K_MMU_WP_040;
695 *prot &= ~PAGE_WRITE;
696 if (access_type & ACCESS_STORE) {
697 return -1;
701 /* Pointer Index */
702 entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
704 next = ldl_phys(cs->as, entry);
705 if (!M68K_UDT_VALID(next)) {
706 return -1;
708 if (!(next & M68K_DESC_USED) && !debug) {
709 stl_phys(cs->as, entry, next | M68K_DESC_USED);
711 if (next & M68K_DESC_WRITEPROT) {
712 if (access_type & ACCESS_PTEST) {
713 env->mmu.mmusr |= M68K_MMU_WP_040;
715 *prot &= ~PAGE_WRITE;
716 if (access_type & ACCESS_STORE) {
717 return -1;
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);
728 next = ldl_phys(cs->as, entry);
730 if (!M68K_PDT_VALID(next)) {
731 return -1;
733 if (M68K_PDT_INDIRECT(next)) {
734 next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next));
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);
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));
746 } else {
747 if (!(next & M68K_DESC_USED) && !debug) {
748 stl_phys(cs->as, entry, next | M68K_DESC_USED);
752 if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
753 page_bits = 13;
754 } else {
755 page_bits = 12;
757 *page_size = 1 << page_bits;
758 page_mask = ~(*page_size - 1);
759 *physical = next & page_mask;
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;
767 if (next & M68K_DESC_WRITEPROT) {
768 *prot &= ~PAGE_WRITE;
769 if (access_type & ACCESS_STORE) {
770 return -1;
773 if (next & M68K_DESC_SUPERONLY) {
774 if ((access_type & ACCESS_SUPER) == 0) {
775 return -1;
779 return 0;
782 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
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;
791 if ((env->mmu.tcr & M68K_TCR_ENABLED) == 0) {
792 /* MMU disabled */
793 return addr;
796 access_type = ACCESS_DATA | ACCESS_DEBUG;
797 if (env->sr & SR_S) {
798 access_type |= ACCESS_SUPER;
800 if (get_physical_address(env, &phys_addr, &prot,
801 addr, access_type, &page_size) != 0) {
802 return -1;
804 return phys_addr;
807 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
808 int mmu_idx)
810 M68kCPU *cpu = M68K_CPU(cs);
811 CPUM68KState *env = &cpu->env;
812 hwaddr physical;
813 int prot;
814 int access_type;
815 int ret;
816 target_ulong page_size;
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;
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;
837 if (mmu_idx != MMU_USER_IDX) {
838 access_type |= ACCESS_SUPER;
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;
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;
863 if (access_type & ACCESS_SUPER) {
864 env->mmu.ssw |= M68K_TM_040_SUPER;
866 if (access_type & ACCESS_CODE) {
867 env->mmu.ssw |= M68K_TM_040_CODE;
868 } else {
869 env->mmu.ssw |= M68K_TM_040_DATA;
871 if (!(access_type & ACCESS_STORE)) {
872 env->mmu.ssw |= M68K_RW_040;
874 env->mmu.ar = address;
875 cs->exception_index = EXCP_ACCESS;
876 return 1;
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. */
883 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
885 CPUState *cs = CPU(cpu);
886 CPUM68KState *env = &cpu->env;
888 env->pending_level = level;
889 env->pending_vector = vector;
890 if (level) {
891 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
892 } else {
893 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
897 #endif
899 uint32_t HELPER(bitrev)(uint32_t x)
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);
907 uint32_t HELPER(ff1)(uint32_t x)
909 int n;
910 for (n = 32; x; n--)
911 x >>= 1;
912 return n;
915 uint32_t HELPER(sats)(uint32_t val, uint32_t v)
917 /* The result has the opposite sign to the original value. */
918 if ((int32_t)v < 0) {
919 val = (((int32_t)val) >> 31) ^ SIGNBIT;
921 return val;
924 void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
926 env->sr = sr & 0xffe0;
927 cpu_m68k_set_ccr(env, sr);
928 m68k_switch_sp(env);
931 void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
933 cpu_m68k_set_sr(env, val);
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. */
940 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
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;
951 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
953 int64_t product;
954 int64_t res;
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;
968 return res;
971 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
973 uint64_t product;
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);
985 return product;
988 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
990 uint64_t product;
991 uint32_t remainder;
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;
1004 return product;
1007 void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
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;
1016 if (env->macsr & MACSR_V) {
1017 env->macsr |= MACSR_PAV0 << acc;
1018 if (env->macsr & MACSR_OMC) {
1019 /* The result is saturated to 32 bits, despite overflow occurring
1020 at 48 bits. Seems weird, but that's what the hardware docs
1021 say. */
1022 result = (result >> 63) ^ 0x7fffffff;
1025 env->macc[acc] = result;
1028 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
1030 uint64_t val;
1032 val = env->macc[acc];
1033 if (val & (0xffffull << 48)) {
1034 env->macsr |= MACSR_V;
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);
1047 env->macc[acc] = val;
1050 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
1052 int64_t sum;
1053 int64_t result;
1055 sum = env->macc[acc];
1056 result = (sum << 16) >> 16;
1057 if (result != sum) {
1058 env->macsr |= MACSR_V;
1060 if (env->macsr & MACSR_V) {
1061 env->macsr |= MACSR_PAV0 << acc;
1062 if (env->macsr & MACSR_OMC) {
1063 result = (result >> 63) ^ 0x7fffffffffffll;
1066 env->macc[acc] = result;
1069 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
1071 uint64_t val;
1072 val = env->macc[acc];
1073 if (val == 0) {
1074 env->macsr |= MACSR_Z;
1075 } else if (val & (1ull << 47)) {
1076 env->macsr |= MACSR_N;
1078 if (env->macsr & (MACSR_PAV0 << acc)) {
1079 env->macsr |= MACSR_V;
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;
1095 #define EXTSIGN(val, index) ( \
1096 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
1099 #define COMPUTE_CCR(op, x, n, z, v, c) { \
1100 switch (op) { \
1101 case CC_OP_FLAGS: \
1102 /* Everything in place. */ \
1103 break; \
1104 case CC_OP_ADDB: \
1105 case CC_OP_ADDW: \
1106 case CC_OP_ADDL: \
1107 res = n; \
1108 src2 = v; \
1109 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
1110 c = x; \
1111 z = n; \
1112 v = (res ^ src1) & ~(src1 ^ src2); \
1113 break; \
1114 case CC_OP_SUBB: \
1115 case CC_OP_SUBW: \
1116 case CC_OP_SUBL: \
1117 res = n; \
1118 src2 = v; \
1119 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
1120 c = x; \
1121 z = n; \
1122 v = (res ^ src1) & (src1 ^ src2); \
1123 break; \
1124 case CC_OP_CMPB: \
1125 case CC_OP_CMPW: \
1126 case CC_OP_CMPL: \
1127 src1 = n; \
1128 src2 = v; \
1129 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
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); \
1142 } while (0)
1144 uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
1146 uint32_t x, c, n, z, v;
1147 uint32_t res, src1, src2;
1149 x = env->cc_x;
1150 n = env->cc_n;
1151 z = env->cc_z;
1152 v = env->cc_v;
1153 c = env->cc_c;
1155 COMPUTE_CCR(env->cc_op, x, n, z, v, c);
1157 n = n >> 31;
1158 z = (z == 0);
1159 v = v >> 31;
1161 return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
1164 uint32_t HELPER(get_ccr)(CPUM68KState *env)
1166 return cpu_m68k_get_ccr(env);
1169 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
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;
1179 void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
1181 cpu_m68k_set_ccr(env, ccr);
1184 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
1186 uint32_t res, src1, src2;
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;
1192 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
1194 int rem;
1195 uint32_t result;
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;
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;
1225 } else {
1226 if (val != (uint32_t)val) {
1227 result = ((uint32_t)(val >> 63) & 0x7fffffff);
1228 } else {
1229 result = (uint32_t)val;
1232 } else {
1233 /* No saturation. */
1234 if (env->macsr & MACSR_SU) {
1235 result = val & 0xffff;
1236 } else {
1237 result = (uint32_t)val;
1240 return result;
1243 uint32_t HELPER(get_macs)(uint64_t val)
1245 if (val == (int32_t)val) {
1246 return (int32_t)val;
1247 } else {
1248 return (val >> 61) ^ ~SIGNBIT;
1252 uint32_t HELPER(get_macu)(uint64_t val)
1254 if ((val >> 32) == 0) {
1255 return (uint32_t)val;
1256 } else {
1257 return 0xffffffffu;
1261 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
1263 uint32_t val;
1264 val = env->macc[acc] & 0x00ff;
1265 val |= (env->macc[acc] >> 32) & 0xff00;
1266 val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
1267 val |= (env->macc[acc + 1] >> 16) & 0xff000000;
1268 return val;
1271 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
1273 uint32_t val;
1274 val = (env->macc[acc] >> 32) & 0xffff;
1275 val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
1276 return val;
1279 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
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;
1295 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
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;
1309 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
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;
1320 #if defined(CONFIG_SOFTMMU)
1321 void HELPER(ptest)(CPUM68KState *env, uint32_t addr, uint32_t is_read)
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;
1331 access_type = ACCESS_PTEST;
1332 if (env->dfc & 4) {
1333 access_type |= ACCESS_SUPER;
1335 if ((env->dfc & 3) == 2) {
1336 access_type |= ACCESS_CODE;
1338 if (!is_read) {
1339 access_type |= ACCESS_STORE;
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);
1355 void HELPER(pflush)(CPUM68KState *env, uint32_t addr, uint32_t opmode)
1357 M68kCPU *cpu = m68k_env_get_cpu(env);
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;
1373 void HELPER(reset)(CPUM68KState *env)
1375 /* FIXME: reset all except CPU */
1377 #endif