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 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". */
  31static 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
  48static 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
  62void 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
  76static 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
  90static 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
 103M68kCPU *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
 123void 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
 135void 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
 157void 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
 191void 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
 204int 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.  */
 219hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 220{
 221    return addr;
 222}
 223
 224int 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.  */
 239void 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
 255uint32_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
 263uint32_t HELPER(ff1)(uint32_t x)
 264{
 265    int n;
 266    for (n = 32; x; n--)
 267        x >>= 1;
 268    return n;
 269}
 270
 271uint32_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
 280void 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
 287uint32_t HELPER(shl_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
 288{
 289    uint64_t result;
 290
 291    shift &= 63;
 292    result = (uint64_t)val << shift;
 293
 294    env->cc_c = (result >> 32) & 1;
 295    env->cc_n = result;
 296    env->cc_z = result;
 297    env->cc_v = 0;
 298    env->cc_x = shift ? env->cc_c : env->cc_x;
 299
 300    return result;
 301}
 302
 303uint32_t HELPER(shr_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
 304{
 305    uint64_t temp;
 306    uint32_t result;
 307
 308    shift &= 63;
 309    temp = (uint64_t)val << 32 >> shift;
 310    result = temp >> 32;
 311
 312    env->cc_c = (temp >> 31) & 1;
 313    env->cc_n = result;
 314    env->cc_z = result;
 315    env->cc_v = 0;
 316    env->cc_x = shift ? env->cc_c : env->cc_x;
 317
 318    return result;
 319}
 320
 321uint32_t HELPER(sar_cc)(CPUM68KState *env, uint32_t val, uint32_t shift)
 322{
 323    uint64_t temp;
 324    uint32_t result;
 325
 326    shift &= 63;
 327    temp = (int64_t)val << 32 >> shift;
 328    result = temp >> 32;
 329
 330    env->cc_c = (temp >> 31) & 1;
 331    env->cc_n = result;
 332    env->cc_z = result;
 333    env->cc_v = result ^ val;
 334    env->cc_x = shift ? env->cc_c : env->cc_x;
 335
 336    return result;
 337}
 338
 339/* FPU helpers.  */
 340uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val)
 341{
 342    return float64_to_int32(val, &env->fp_status);
 343}
 344
 345float32 HELPER(f64_to_f32)(CPUM68KState *env, float64 val)
 346{
 347    return float64_to_float32(val, &env->fp_status);
 348}
 349
 350float64 HELPER(i32_to_f64)(CPUM68KState *env, uint32_t val)
 351{
 352    return int32_to_float64(val, &env->fp_status);
 353}
 354
 355float64 HELPER(f32_to_f64)(CPUM68KState *env, float32 val)
 356{
 357    return float32_to_float64(val, &env->fp_status);
 358}
 359
 360float64 HELPER(iround_f64)(CPUM68KState *env, float64 val)
 361{
 362    return float64_round_to_int(val, &env->fp_status);
 363}
 364
 365float64 HELPER(itrunc_f64)(CPUM68KState *env, float64 val)
 366{
 367    return float64_trunc_to_int(val, &env->fp_status);
 368}
 369
 370float64 HELPER(sqrt_f64)(CPUM68KState *env, float64 val)
 371{
 372    return float64_sqrt(val, &env->fp_status);
 373}
 374
 375float64 HELPER(abs_f64)(float64 val)
 376{
 377    return float64_abs(val);
 378}
 379
 380float64 HELPER(chs_f64)(float64 val)
 381{
 382    return float64_chs(val);
 383}
 384
 385float64 HELPER(add_f64)(CPUM68KState *env, float64 a, float64 b)
 386{
 387    return float64_add(a, b, &env->fp_status);
 388}
 389
 390float64 HELPER(sub_f64)(CPUM68KState *env, float64 a, float64 b)
 391{
 392    return float64_sub(a, b, &env->fp_status);
 393}
 394
 395float64 HELPER(mul_f64)(CPUM68KState *env, float64 a, float64 b)
 396{
 397    return float64_mul(a, b, &env->fp_status);
 398}
 399
 400float64 HELPER(div_f64)(CPUM68KState *env, float64 a, float64 b)
 401{
 402    return float64_div(a, b, &env->fp_status);
 403}
 404
 405float64 HELPER(sub_cmp_f64)(CPUM68KState *env, float64 a, float64 b)
 406{
 407    /* ??? This may incorrectly raise exceptions.  */
 408    /* ??? Should flush denormals to zero.  */
 409    float64 res;
 410    res = float64_sub(a, b, &env->fp_status);
 411    if (float64_is_quiet_nan(res, &env->fp_status)) {
 412        /* +/-inf compares equal against itself, but sub returns nan.  */
 413        if (!float64_is_quiet_nan(a, &env->fp_status)
 414            && !float64_is_quiet_nan(b, &env->fp_status)) {
 415            res = float64_zero;
 416            if (float64_lt_quiet(a, res, &env->fp_status))
 417                res = float64_chs(res);
 418        }
 419    }
 420    return res;
 421}
 422
 423uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
 424{
 425    return float64_compare_quiet(val, float64_zero, &env->fp_status);
 426}
 427
 428/* MAC unit.  */
 429/* FIXME: The MAC unit implementation is a bit of a mess.  Some helpers
 430   take values,  others take register numbers and manipulate the contents
 431   in-place.  */
 432void HELPER(mac_move)(CPUM68KState *env, uint32_t dest, uint32_t src)
 433{
 434    uint32_t mask;
 435    env->macc[dest] = env->macc[src];
 436    mask = MACSR_PAV0 << dest;
 437    if (env->macsr & (MACSR_PAV0 << src))
 438        env->macsr |= mask;
 439    else
 440        env->macsr &= ~mask;
 441}
 442
 443uint64_t HELPER(macmuls)(CPUM68KState *env, uint32_t op1, uint32_t op2)
 444{
 445    int64_t product;
 446    int64_t res;
 447
 448    product = (uint64_t)op1 * op2;
 449    res = (product << 24) >> 24;
 450    if (res != product) {
 451        env->macsr |= MACSR_V;
 452        if (env->macsr & MACSR_OMC) {
 453            /* Make sure the accumulate operation overflows.  */
 454            if (product < 0)
 455                res = ~(1ll << 50);
 456            else
 457                res = 1ll << 50;
 458        }
 459    }
 460    return res;
 461}
 462
 463uint64_t HELPER(macmulu)(CPUM68KState *env, uint32_t op1, uint32_t op2)
 464{
 465    uint64_t product;
 466
 467    product = (uint64_t)op1 * op2;
 468    if (product & (0xffffffull << 40)) {
 469        env->macsr |= MACSR_V;
 470        if (env->macsr & MACSR_OMC) {
 471            /* Make sure the accumulate operation overflows.  */
 472            product = 1ll << 50;
 473        } else {
 474            product &= ((1ull << 40) - 1);
 475        }
 476    }
 477    return product;
 478}
 479
 480uint64_t HELPER(macmulf)(CPUM68KState *env, uint32_t op1, uint32_t op2)
 481{
 482    uint64_t product;
 483    uint32_t remainder;
 484
 485    product = (uint64_t)op1 * op2;
 486    if (env->macsr & MACSR_RT) {
 487        remainder = product & 0xffffff;
 488        product >>= 24;
 489        if (remainder > 0x800000)
 490            product++;
 491        else if (remainder == 0x800000)
 492            product += (product & 1);
 493    } else {
 494        product >>= 24;
 495    }
 496    return product;
 497}
 498
 499void HELPER(macsats)(CPUM68KState *env, uint32_t acc)
 500{
 501    int64_t tmp;
 502    int64_t result;
 503    tmp = env->macc[acc];
 504    result = ((tmp << 16) >> 16);
 505    if (result != tmp) {
 506        env->macsr |= MACSR_V;
 507    }
 508    if (env->macsr & MACSR_V) {
 509        env->macsr |= MACSR_PAV0 << acc;
 510        if (env->macsr & MACSR_OMC) {
 511            /* The result is saturated to 32 bits, despite overflow occurring
 512               at 48 bits.  Seems weird, but that's what the hardware docs
 513               say.  */
 514            result = (result >> 63) ^ 0x7fffffff;
 515        }
 516    }
 517    env->macc[acc] = result;
 518}
 519
 520void HELPER(macsatu)(CPUM68KState *env, uint32_t acc)
 521{
 522    uint64_t val;
 523
 524    val = env->macc[acc];
 525    if (val & (0xffffull << 48)) {
 526        env->macsr |= MACSR_V;
 527    }
 528    if (env->macsr & MACSR_V) {
 529        env->macsr |= MACSR_PAV0 << acc;
 530        if (env->macsr & MACSR_OMC) {
 531            if (val > (1ull << 53))
 532                val = 0;
 533            else
 534                val = (1ull << 48) - 1;
 535        } else {
 536            val &= ((1ull << 48) - 1);
 537        }
 538    }
 539    env->macc[acc] = val;
 540}
 541
 542void HELPER(macsatf)(CPUM68KState *env, uint32_t acc)
 543{
 544    int64_t sum;
 545    int64_t result;
 546
 547    sum = env->macc[acc];
 548    result = (sum << 16) >> 16;
 549    if (result != sum) {
 550        env->macsr |= MACSR_V;
 551    }
 552    if (env->macsr & MACSR_V) {
 553        env->macsr |= MACSR_PAV0 << acc;
 554        if (env->macsr & MACSR_OMC) {
 555            result = (result >> 63) ^ 0x7fffffffffffll;
 556        }
 557    }
 558    env->macc[acc] = result;
 559}
 560
 561void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc)
 562{
 563    uint64_t val;
 564    val = env->macc[acc];
 565    if (val == 0) {
 566        env->macsr |= MACSR_Z;
 567    } else if (val & (1ull << 47)) {
 568        env->macsr |= MACSR_N;
 569    }
 570    if (env->macsr & (MACSR_PAV0 << acc)) {
 571        env->macsr |= MACSR_V;
 572    }
 573    if (env->macsr & MACSR_FI) {
 574        val = ((int64_t)val) >> 40;
 575        if (val != 0 && val != -1)
 576            env->macsr |= MACSR_EV;
 577    } else if (env->macsr & MACSR_SU) {
 578        val = ((int64_t)val) >> 32;
 579        if (val != 0 && val != -1)
 580            env->macsr |= MACSR_EV;
 581    } else {
 582        if ((val >> 32) != 0)
 583            env->macsr |= MACSR_EV;
 584    }
 585}
 586
 587#define EXTSIGN(val, index) (     \
 588    (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
 589)
 590
 591#define COMPUTE_CCR(op, x, n, z, v, c) {                                   \
 592    switch (op) {                                                          \
 593    case CC_OP_FLAGS:                                                      \
 594        /* Everything in place.  */                                        \
 595        break;                                                             \
 596    case CC_OP_ADDB:                                                       \
 597    case CC_OP_ADDW:                                                       \
 598    case CC_OP_ADDL:                                                       \
 599        res = n;                                                           \
 600        src2 = v;                                                          \
 601        src1 = EXTSIGN(res - src2, op - CC_OP_ADDB);                       \
 602        c = x;                                                             \
 603        z = n;                                                             \
 604        v = (res ^ src1) & ~(src1 ^ src2);                                 \
 605        break;                                                             \
 606    case CC_OP_SUBB:                                                       \
 607    case CC_OP_SUBW:                                                       \
 608    case CC_OP_SUBL:                                                       \
 609        res = n;                                                           \
 610        src2 = v;                                                          \
 611        src1 = EXTSIGN(res + src2, op - CC_OP_SUBB);                       \
 612        c = x;                                                             \
 613        z = n;                                                             \
 614        v = (res ^ src1) & (src1 ^ src2);                                  \
 615        break;                                                             \
 616    case CC_OP_CMPB:                                                       \
 617    case CC_OP_CMPW:                                                       \
 618    case CC_OP_CMPL:                                                       \
 619        src1 = n;                                                          \
 620        src2 = v;                                                          \
 621        res = EXTSIGN(src1 - src2, op - CC_OP_CMPB);                       \
 622        n = res;                                                           \
 623        z = res;                                                           \
 624        c = src1 < src2;                                                   \
 625        v = (res ^ src1) & (src1 ^ src2);                                  \
 626        break;                                                             \
 627    case CC_OP_LOGIC:                                                      \
 628        c = v = 0;                                                         \
 629        z = n;                                                             \
 630        break;                                                             \
 631    default:                                                               \
 632        cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op);         \
 633    }                                                                      \
 634} while (0)
 635
 636uint32_t cpu_m68k_get_ccr(CPUM68KState *env)
 637{
 638    uint32_t x, c, n, z, v;
 639    uint32_t res, src1, src2;
 640
 641    x = env->cc_x;
 642    n = env->cc_n;
 643    z = env->cc_z;
 644    v = env->cc_v;
 645    c = env->cc_c;
 646
 647    COMPUTE_CCR(env->cc_op, x, n, z, v, c);
 648
 649    n = n >> 31;
 650    z = (z == 0);
 651    v = v >> 31;
 652
 653    return x * CCF_X + n * CCF_N + z * CCF_Z + v * CCF_V + c * CCF_C;
 654}
 655
 656uint32_t HELPER(get_ccr)(CPUM68KState *env)
 657{
 658    return cpu_m68k_get_ccr(env);
 659}
 660
 661void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr)
 662{
 663    env->cc_x = (ccr & CCF_X ? 1 : 0);
 664    env->cc_n = (ccr & CCF_N ? -1 : 0);
 665    env->cc_z = (ccr & CCF_Z ? 0 : 1);
 666    env->cc_v = (ccr & CCF_V ? -1 : 0);
 667    env->cc_c = (ccr & CCF_C ? 1 : 0);
 668    env->cc_op = CC_OP_FLAGS;
 669}
 670
 671void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr)
 672{
 673    cpu_m68k_set_ccr(env, ccr);
 674}
 675
 676void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op)
 677{
 678    uint32_t res, src1, src2;
 679
 680    COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c);
 681    env->cc_op = CC_OP_FLAGS;
 682}
 683
 684uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val)
 685{
 686    int rem;
 687    uint32_t result;
 688
 689    if (env->macsr & MACSR_SU) {
 690        /* 16-bit rounding.  */
 691        rem = val & 0xffffff;
 692        val = (val >> 24) & 0xffffu;
 693        if (rem > 0x800000)
 694            val++;
 695        else if (rem == 0x800000)
 696            val += (val & 1);
 697    } else if (env->macsr & MACSR_RT) {
 698        /* 32-bit rounding.  */
 699        rem = val & 0xff;
 700        val >>= 8;
 701        if (rem > 0x80)
 702            val++;
 703        else if (rem == 0x80)
 704            val += (val & 1);
 705    } else {
 706        /* No rounding.  */
 707        val >>= 8;
 708    }
 709    if (env->macsr & MACSR_OMC) {
 710        /* Saturate.  */
 711        if (env->macsr & MACSR_SU) {
 712            if (val != (uint16_t) val) {
 713                result = ((val >> 63) ^ 0x7fff) & 0xffff;
 714            } else {
 715                result = val & 0xffff;
 716            }
 717        } else {
 718            if (val != (uint32_t)val) {
 719                result = ((uint32_t)(val >> 63) & 0x7fffffff);
 720            } else {
 721                result = (uint32_t)val;
 722            }
 723        }
 724    } else {
 725        /* No saturation.  */
 726        if (env->macsr & MACSR_SU) {
 727            result = val & 0xffff;
 728        } else {
 729            result = (uint32_t)val;
 730        }
 731    }
 732    return result;
 733}
 734
 735uint32_t HELPER(get_macs)(uint64_t val)
 736{
 737    if (val == (int32_t)val) {
 738        return (int32_t)val;
 739    } else {
 740        return (val >> 61) ^ ~SIGNBIT;
 741    }
 742}
 743
 744uint32_t HELPER(get_macu)(uint64_t val)
 745{
 746    if ((val >> 32) == 0) {
 747        return (uint32_t)val;
 748    } else {
 749        return 0xffffffffu;
 750    }
 751}
 752
 753uint32_t HELPER(get_mac_extf)(CPUM68KState *env, uint32_t acc)
 754{
 755    uint32_t val;
 756    val = env->macc[acc] & 0x00ff;
 757    val |= (env->macc[acc] >> 32) & 0xff00;
 758    val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
 759    val |= (env->macc[acc + 1] >> 16) & 0xff000000;
 760    return val;
 761}
 762
 763uint32_t HELPER(get_mac_exti)(CPUM68KState *env, uint32_t acc)
 764{
 765    uint32_t val;
 766    val = (env->macc[acc] >> 32) & 0xffff;
 767    val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
 768    return val;
 769}
 770
 771void HELPER(set_mac_extf)(CPUM68KState *env, uint32_t val, uint32_t acc)
 772{
 773    int64_t res;
 774    int32_t tmp;
 775    res = env->macc[acc] & 0xffffffff00ull;
 776    tmp = (int16_t)(val & 0xff00);
 777    res |= ((int64_t)tmp) << 32;
 778    res |= val & 0xff;
 779    env->macc[acc] = res;
 780    res = env->macc[acc + 1] & 0xffffffff00ull;
 781    tmp = (val & 0xff000000);
 782    res |= ((int64_t)tmp) << 16;
 783    res |= (val >> 16) & 0xff;
 784    env->macc[acc + 1] = res;
 785}
 786
 787void HELPER(set_mac_exts)(CPUM68KState *env, uint32_t val, uint32_t acc)
 788{
 789    int64_t res;
 790    int32_t tmp;
 791    res = (uint32_t)env->macc[acc];
 792    tmp = (int16_t)val;
 793    res |= ((int64_t)tmp) << 32;
 794    env->macc[acc] = res;
 795    res = (uint32_t)env->macc[acc + 1];
 796    tmp = val & 0xffff0000;
 797    res |= (int64_t)tmp << 16;
 798    env->macc[acc + 1] = res;
 799}
 800
 801void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
 802{
 803    uint64_t res;
 804    res = (uint32_t)env->macc[acc];
 805    res |= ((uint64_t)(val & 0xffff)) << 32;
 806    env->macc[acc] = res;
 807    res = (uint32_t)env->macc[acc + 1];
 808    res |= (uint64_t)(val & 0xffff0000) << 16;
 809    env->macc[acc + 1] = res;
 810}
 811