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