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