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