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