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