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