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