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 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 * 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 26 #include "exec/helper-proto.h" 27 28 #define SIGNBIT (1u << 31) 29 30 /* Sort alphabetically, except for "any". */ 31 static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) 32 { 33 ObjectClass *class_a = (ObjectClass *)a; 34 ObjectClass *class_b = (ObjectClass *)b; 35 const char *name_a, *name_b; 36 37 name_a = object_class_get_name(class_a); 38 name_b = object_class_get_name(class_b); 39 if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) { 40 return 1; 41 } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) { 42 return -1; 43 } else { 44 return strcasecmp(name_a, name_b); 45 } 46 } 47 48 static void m68k_cpu_list_entry(gpointer data, gpointer user_data) 49 { 50 ObjectClass *c = data; 51 CPUListState *s = user_data; 52 const char *typename; 53 char *name; 54 55 typename = object_class_get_name(c); 56 name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU)); 57 (*s->cpu_fprintf)(s->file, "%s\n", 58 name); 59 g_free(name); 60 } 61 62 void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) 63 { 64 CPUListState s = { 65 .file = f, 66 .cpu_fprintf = cpu_fprintf, 67 }; 68 GSList *list; 69 70 list = object_class_get_list(TYPE_M68K_CPU, false); 71 list = g_slist_sort(list, m68k_cpu_list_compare); 72 g_slist_foreach(list, m68k_cpu_list_entry, &s); 73 g_slist_free(list); 74 } 75 76 static int fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 77 { 78 if (n < 8) { 79 stfq_p(mem_buf, env->fregs[n]); 80 return 8; 81 } 82 if (n < 11) { 83 /* FP control registers (not implemented) */ 84 memset(mem_buf, 0, 4); 85 return 4; 86 } 87 return 0; 88 } 89 90 static int fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) 91 { 92 if (n < 8) { 93 env->fregs[n] = ldfq_p(mem_buf); 94 return 8; 95 } 96 if (n < 11) { 97 /* FP control registers (not implemented) */ 98 return 4; 99 } 100 return 0; 101 } 102 103 M68kCPU *cpu_m68k_init(const char *cpu_model) 104 { 105 M68kCPU *cpu; 106 CPUM68KState *env; 107 ObjectClass *oc; 108 109 oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model); 110 if (oc == NULL) { 111 return NULL; 112 } 113 cpu = M68K_CPU(object_new(object_class_get_name(oc))); 114 env = &cpu->env; 115 116 register_m68k_insns(env); 117 118 object_property_set_bool(OBJECT(cpu), true, "realized", NULL); 119 120 return cpu; 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, fpu_gdb_get_reg, fpu_gdb_set_reg, 130 11, "cf-fp.xml", 18); 131 } 132 /* TODO: Add [E]MAC registers. */ 133 } 134 135 void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) 136 { 137 M68kCPU *cpu = m68k_env_get_cpu(env); 138 139 switch (reg) { 140 case 0x02: /* CACR */ 141 env->cacr = val; 142 m68k_switch_sp(env); 143 break; 144 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */ 145 /* TODO: Implement Access Control Registers. */ 146 break; 147 case 0x801: /* VBR */ 148 env->vbr = val; 149 break; 150 /* TODO: Implement control registers. */ 151 default: 152 cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", 153 reg, val); 154 } 155 } 156 157 void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) 158 { 159 uint32_t acc; 160 int8_t exthigh; 161 uint8_t extlow; 162 uint64_t regval; 163 int i; 164 if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { 165 for (i = 0; i < 4; i++) { 166 regval = env->macc[i]; 167 exthigh = regval >> 40; 168 if (env->macsr & MACSR_FI) { 169 acc = regval >> 8; 170 extlow = regval; 171 } else { 172 acc = regval; 173 extlow = regval >> 32; 174 } 175 if (env->macsr & MACSR_FI) { 176 regval = (((uint64_t)acc) << 8) | extlow; 177 regval |= ((int64_t)exthigh) << 40; 178 } else if (env->macsr & MACSR_SU) { 179 regval = acc | (((int64_t)extlow) << 32); 180 regval |= ((int64_t)exthigh) << 40; 181 } else { 182 regval = acc | (((uint64_t)extlow) << 32); 183 regval |= ((uint64_t)(uint8_t)exthigh) << 40; 184 } 185 env->macc[i] = regval; 186 } 187 } 188 env->macsr = val; 189 } 190 191 void m68k_switch_sp(CPUM68KState *env) 192 { 193 int new_sp; 194 195 env->sp[env->current_sp] = env->aregs[7]; 196 new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) 197 ? M68K_SSP : M68K_USP; 198 env->aregs[7] = env->sp[new_sp]; 199 env->current_sp = new_sp; 200 } 201 202 #if defined(CONFIG_USER_ONLY) 203 204 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 205 int mmu_idx) 206 { 207 M68kCPU *cpu = M68K_CPU(cs); 208 209 cs->exception_index = EXCP_ACCESS; 210 cpu->env.mmu.ar = address; 211 return 1; 212 } 213 214 #else 215 216 /* MMU */ 217 218 /* TODO: This will need fixing once the MMU is implemented. */ 219 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 220 { 221 return addr; 222 } 223 224 int m68k_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 225 int mmu_idx) 226 { 227 int prot; 228 229 address &= TARGET_PAGE_MASK; 230 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 231 tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); 232 return 0; 233 } 234 235 /* Notify CPU of a pending interrupt. Prioritization and vectoring should 236 be handled by the interrupt controller. Real hardware only requests 237 the vector when the interrupt is acknowledged by the CPU. For 238 simplicitly we calculate it when the interrupt is signalled. */ 239 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) 240 { 241 CPUState *cs = CPU(cpu); 242 CPUM68KState *env = &cpu->env; 243 244 env->pending_level = level; 245 env->pending_vector = vector; 246 if (level) { 247 cpu_interrupt(cs, CPU_INTERRUPT_HARD); 248 } else { 249 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 250 } 251 } 252 253 #endif 254 255 uint32_t HELPER(bitrev)(uint32_t x) 256 { 257 x = ((x >> 1) & 0x55555555u) | ((x << 1) & 0xaaaaaaaau); 258 x = ((x >> 2) & 0x33333333u) | ((x << 2) & 0xccccccccu); 259 x = ((x >> 4) & 0x0f0f0f0fu) | ((x << 4) & 0xf0f0f0f0u); 260 return bswap32(x); 261 } 262 263 uint32_t HELPER(ff1)(uint32_t x) 264 { 265 int n; 266 for (n = 32; x; n--) 267 x >>= 1; 268 return n; 269 } 270 271 uint32_t HELPER(sats)(uint32_t val, uint32_t v) 272 { 273 /* The result has the opposite sign to the original value. */ 274 if ((int32_t)v < 0) { 275 val = (((int32_t)val) >> 31) ^ SIGNBIT; 276 } 277 return val; 278 } 279 280 void HELPER(set_sr)(CPUM68KState *env, uint32_t val) 281 { 282 env->sr = val & 0xffe0; 283 cpu_m68k_set_ccr(env, val); 284 m68k_switch_sp(env); 285 } 286 287 288 /* MAC unit. */ 289 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers 290 take values, others take register numbers and manipulate the contents 291 in-place. */ 292 void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src) 293 { 294 uint32_t mask; 295 env->macc[dest] = env->macc[src]; 296 mask = MACSR_PAV0 << dest; 297 if (env->macsr & (MACSR_PAV0 << src)) 298 env->macsr |= mask; 299 else 300 env->macsr &= ~mask; 301 } 302 303 uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2) 304 { 305 int64_t product; 306 int64_t res; 307 308 product = (uint64_t)op1 * op2; 309 res = (product << 24) >> 24; 310 if (res != product) { 311 env->macsr |= MACSR_V; 312 if (env->macsr & MACSR_OMC) { 313 /* Make sure the accumulate operation overflows. */ 314 if (product < 0) 315 res = ~(1ll << 50); 316 else 317 res = 1ll << 50; 318 } 319 } 320 return res; 321 } 322 323 uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2) 324 { 325 uint64_t product; 326 327 product = (uint64_t)op1 * op2; 328 if (product & (0xffffffull << 40)) { 329 env->macsr |= MACSR_V; 330 if (env->macsr & MACSR_OMC) { 331 /* Make sure the accumulate operation overflows. */ 332 product = 1ll << 50; 333 } else { 334 product &= ((1ull << 40) - 1); 335 } 336 } 337 return product; 338 } 339 340 uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2) 341 { 342 uint64_t product; 343 uint32_t remainder; 344 345 product = (uint64_t)op1 * op2; 346 if (env->macsr & MACSR_RT) { 347 remainder = product & 0xffffff; 348 product >>= 24; 349 if (remainder > 0x800000) 350 product++; 351 else if (remainder == 0x800000) 352 product += (product & 1); 353 } else { 354 product >>= 24; 355 } 356 return product; 357 } 358 359 void HELPER(macsats)(CPUM68KState *env, uint32_t acc) 360 { 361 int64_t tmp; 362 int64_t result; 363 tmp = env->macc[acc]; 364 result = ((tmp << 16) >> 16); 365 if (result != tmp) { 366 env->macsr |= MACSR_V; 367 } 368 if (env->macsr & MACSR_V) { 369 env->macsr |= MACSR_PAV0 << acc; 370 if (env->macsr & MACSR_OMC) { 371 /* The result is saturated to 32 bits, despite overflow occurring 372 at 48 bits. Seems weird, but that's what the hardware docs 373 say. */ 374 result = (result >> 63) ^ 0x7fffffff; 375 } 376 } 377 env->macc[acc] = result; 378 } 379 380 void HELPER(macsatu)(CPUM68KState *env, uint32_t acc) 381 { 382 uint64_t val; 383 384 val = env->macc[acc]; 385 if (val & (0xffffull << 48)) { 386 env->macsr |= MACSR_V; 387 } 388 if (env->macsr & MACSR_V) { 389 env->macsr |= MACSR_PAV0 << acc; 390 if (env->macsr & MACSR_OMC) { 391 if (val > (1ull << 53)) 392 val = 0; 393 else 394 val = (1ull << 48) - 1; 395 } else { 396 val &= ((1ull << 48) - 1); 397 } 398 } 399 env->macc[acc] = val; 400 } 401 402 void HELPER(macsatf)(CPUM68KState *env, uint32_t acc) 403 { 404 int64_t sum; 405 int64_t result; 406 407 sum = env->macc[acc]; 408 result = (sum << 16) >> 16; 409 if (result != sum) { 410 env->macsr |= MACSR_V; 411 } 412 if (env->macsr & MACSR_V) { 413 env->macsr |= MACSR_PAV0 << acc; 414 if (env->macsr & MACSR_OMC) { 415 result = (result >> 63) ^ 0x7fffffffffffll; 416 } 417 } 418 env->macc[acc] = result; 419 } 420 421 void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) 422 { 423 uint64_t val; 424 val = env->macc[acc]; 425 if (val == 0) { 426 env->macsr |= MACSR_Z; 427 } else if (val & (1ull << 47)) { 428 env->macsr |= MACSR_N; 429 } 430 if (env->macsr & (MACSR_PAV0 << acc)) { 431 env->macsr |= MACSR_V; 432 } 433 if (env->macsr & MACSR_FI) { 434 val = ((int64_t)val) >> 40; 435 if (val != 0 && val != -1) 436 env->macsr |= MACSR_EV; 437 } else if (env->macsr & MACSR_SU) { 438 val = ((int64_t)val) >> 32; 439 if (val != 0 && val != -1) 440 env->macsr |= MACSR_EV; 441 } else { 442 if ((val >> 32) != 0) 443 env->macsr |= MACSR_EV; 444 } 445 } 446 447 #define EXTSIGN(val, index) ( \ 448 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \ 449 ) 450 451 #define COMPUTE_CCR(op, x, n, z, v, c) { \ 452 switch (op) { \ 453 case CC_OP_FLAGS: \ 454 /* Everything in place. */ \ 455 break; \ 456 case CC_OP_ADDB: \ 457 case CC_OP_ADDW: \ 458 case CC_OP_ADDL: \ 459 res = n; \ 460 src2 = v; \ 461 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \ 462 c = x; \ 463 z = n; \ 464 v = (res ^ src1) & ~(src1 ^ src2); \ 465 break; \ 466 case CC_OP_SUBB: \ 467 case CC_OP_SUBW: \ 468 case CC_OP_SUBL: \ 469 res = n; \ 470 src2 = v; \ 471 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \ 472 c = x; \ 473 z = n; \ 474 v = (res ^ src1) & (src1 ^ src2); \ 475 break; \ 476 case CC_OP_CMPB: \ 477 case CC_OP_CMPW: \ 478 case CC_OP_CMPL: \ 479 src1 = n; \ 480 src2 = v; \ 481 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \ 482 n = res; \ 483 z = res; \ 484 c = src1 < src2; \ 485 v = (res ^ src1) & (src1 ^ src2); \ 486 break; \ 487 case CC_OP_LOGIC: \ 488 c = v = 0; \ 489 z = n; \ 490 break; \ 491 default: \ 492 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \ 493 } \ 494 } while (0) 495 496 uint32_t cpu_m68k_get_ccr(CPUM68KState *env) 497 { 498 uint32_t x, c, n, z, v; 499 uint32_t res, src1, src2; 500 501 x = env->cc_x; 502 n = env->cc_n; 503 z = env->cc_z; 504 v = env->cc_v; 505 c = env->cc_c; 506 507 COMPUTE_CCR(env->cc_op, x, n, z, v, c); 508 509 n = n >> 31; 510 z = (z == 0); 511 v = v >> 31; 512 513 return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C; 514 } 515 516 uint32_t HELPER(get_ccr)(CPUM68KState *env) 517 { 518 return cpu_m68k_get_ccr(env); 519 } 520 521 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) 522 { 523 env->cc_x = (ccr & CCF_X ? 1 : 0); 524 env->cc_n = (ccr & CCF_N ? -1 : 0); 525 env->cc_z = (ccr & CCF_Z ? 0 : 1); 526 env->cc_v = (ccr & CCF_V ? -1 : 0); 527 env->cc_c = (ccr & CCF_C ? 1 : 0); 528 env->cc_op = CC_OP_FLAGS; 529 } 530 531 void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) 532 { 533 cpu_m68k_set_ccr(env, ccr); 534 } 535 536 void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) 537 { 538 uint32_t res, src1, src2; 539 540 COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); 541 env->cc_op = CC_OP_FLAGS; 542 } 543 544 uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) 545 { 546 int rem; 547 uint32_t result; 548 549 if (env->macsr & MACSR_SU) { 550 /* 16-bit rounding. */ 551 rem = val & 0xffffff; 552 val = (val >> 24) & 0xffffu; 553 if (rem > 0x800000) 554 val++; 555 else if (rem == 0x800000) 556 val += (val & 1); 557 } else if (env->macsr & MACSR_RT) { 558 /* 32-bit rounding. */ 559 rem = val & 0xff; 560 val >>= 8; 561 if (rem > 0x80) 562 val++; 563 else if (rem == 0x80) 564 val += (val & 1); 565 } else { 566 /* No rounding. */ 567 val >>= 8; 568 } 569 if (env->macsr & MACSR_OMC) { 570 /* Saturate. */ 571 if (env->macsr & MACSR_SU) { 572 if (val != (uint16_t) val) { 573 result = ((val >> 63) ^ 0x7fff) & 0xffff; 574 } else { 575 result = val & 0xffff; 576 } 577 } else { 578 if (val != (uint32_t)val) { 579 result = ((uint32_t)(val >> 63) & 0x7fffffff); 580 } else { 581 result = (uint32_t)val; 582 } 583 } 584 } else { 585 /* No saturation. */ 586 if (env->macsr & MACSR_SU) { 587 result = val & 0xffff; 588 } else { 589 result = (uint32_t)val; 590 } 591 } 592 return result; 593 } 594 595 uint32_t HELPER(get_macs)(uint64_t val) 596 { 597 if (val == (int32_t)val) { 598 return (int32_t)val; 599 } else { 600 return (val >> 61) ^ ~SIGNBIT; 601 } 602 } 603 604 uint32_t HELPER(get_macu)(uint64_t val) 605 { 606 if ((val >> 32) == 0) { 607 return (uint32_t)val; 608 } else { 609 return 0xffffffffu; 610 } 611 } 612 613 uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc) 614 { 615 uint32_t val; 616 val = env->macc[acc] & 0x00ff; 617 val |= (env->macc[acc] >> 32) & 0xff00; 618 val |= (env->macc[acc + 1] << 16) & 0x00ff0000; 619 val |= (env->macc[acc + 1] >> 16) & 0xff000000; 620 return val; 621 } 622 623 uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc) 624 { 625 uint32_t val; 626 val = (env->macc[acc] >> 32) & 0xffff; 627 val |= (env->macc[acc + 1] >> 16) & 0xffff0000; 628 return val; 629 } 630 631 void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc) 632 { 633 int64_t res; 634 int32_t tmp; 635 res = env->macc[acc] & 0xffffffff00ull; 636 tmp = (int16_t)(val & 0xff00); 637 res |= ((int64_t)tmp) << 32; 638 res |= val & 0xff; 639 env->macc[acc] = res; 640 res = env->macc[acc + 1] & 0xffffffff00ull; 641 tmp = (val & 0xff000000); 642 res |= ((int64_t)tmp) << 16; 643 res |= (val >> 16) & 0xff; 644 env->macc[acc + 1] = res; 645 } 646 647 void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc) 648 { 649 int64_t res; 650 int32_t tmp; 651 res = (uint32_t)env->macc[acc]; 652 tmp = (int16_t)val; 653 res |= ((int64_t)tmp) << 32; 654 env->macc[acc] = res; 655 res = (uint32_t)env->macc[acc + 1]; 656 tmp = val & 0xffff0000; 657 res |= (int64_t)tmp << 16; 658 env->macc[acc + 1] = res; 659 } 660 661 void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) 662 { 663 uint64_t res; 664 res = (uint32_t)env->macc[acc]; 665 res |= ((uint64_t)(val & 0xffff)) << 32; 666 env->macc[acc] = res; 667 res = (uint32_t)env->macc[acc + 1]; 668 res |= (uint64_t)(val & 0xffff0000) << 16; 669 env->macc[acc + 1] = res; 670 } 671