qemu/target/m68k/op_helper.c
<<
>>
Prefs
   1/*
   2 *  M68K helper routines
   3 *
   4 *  Copyright (c) 2007 CodeSourcery
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include "qemu/osdep.h"
  20#include "cpu.h"
  21#include "exec/helper-proto.h"
  22#include "exec/exec-all.h"
  23#include "exec/cpu_ldst.h"
  24#include "exec/semihost.h"
  25
  26#if defined(CONFIG_USER_ONLY)
  27
  28void m68k_cpu_do_interrupt(CPUState *cs)
  29{
  30    cs->exception_index = -1;
  31}
  32
  33static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
  34{
  35}
  36
  37#else
  38
  39/* Try to fill the TLB and return an exception if error. If retaddr is
  40   NULL, it means that the function was called in C code (i.e. not
  41   from generated code or from helper.c) */
  42void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
  43              int mmu_idx, uintptr_t retaddr)
  44{
  45    int ret;
  46
  47    ret = m68k_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
  48    if (unlikely(ret)) {
  49        if (retaddr) {
  50            /* now we have a real cpu fault */
  51            cpu_restore_state(cs, retaddr);
  52        }
  53        cpu_loop_exit(cs);
  54    }
  55}
  56
  57static void do_rte(CPUM68KState *env)
  58{
  59    uint32_t sp;
  60    uint32_t fmt;
  61
  62    sp = env->aregs[7];
  63    fmt = cpu_ldl_kernel(env, sp);
  64    env->pc = cpu_ldl_kernel(env, sp + 4);
  65    sp |= (fmt >> 28) & 3;
  66    env->aregs[7] = sp + 8;
  67
  68    helper_set_sr(env, fmt);
  69}
  70
  71static void do_interrupt_all(CPUM68KState *env, int is_hw)
  72{
  73    CPUState *cs = CPU(m68k_env_get_cpu(env));
  74    uint32_t sp;
  75    uint32_t fmt;
  76    uint32_t retaddr;
  77    uint32_t vector;
  78
  79    fmt = 0;
  80    retaddr = env->pc;
  81
  82    if (!is_hw) {
  83        switch (cs->exception_index) {
  84        case EXCP_RTE:
  85            /* Return from an exception.  */
  86            do_rte(env);
  87            return;
  88        case EXCP_HALT_INSN:
  89            if (semihosting_enabled()
  90                    && (env->sr & SR_S) != 0
  91                    && (env->pc & 3) == 0
  92                    && cpu_lduw_code(env, env->pc - 4) == 0x4e71
  93                    && cpu_ldl_code(env, env->pc) == 0x4e7bf000) {
  94                env->pc += 4;
  95                do_m68k_semihosting(env, env->dregs[0]);
  96                return;
  97            }
  98            cs->halted = 1;
  99            cs->exception_index = EXCP_HLT;
 100            cpu_loop_exit(cs);
 101            return;
 102        }
 103        if (cs->exception_index >= EXCP_TRAP0
 104            && cs->exception_index <= EXCP_TRAP15) {
 105            /* Move the PC after the trap instruction.  */
 106            retaddr += 2;
 107        }
 108    }
 109
 110    vector = cs->exception_index << 2;
 111
 112    fmt |= 0x40000000;
 113    fmt |= vector << 16;
 114    fmt |= env->sr;
 115    fmt |= cpu_m68k_get_ccr(env);
 116
 117    env->sr |= SR_S;
 118    if (is_hw) {
 119        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
 120        env->sr &= ~SR_M;
 121    }
 122    m68k_switch_sp(env);
 123    sp = env->aregs[7];
 124    fmt |= (sp & 3) << 28;
 125
 126    /* ??? This could cause MMU faults.  */
 127    sp &= ~3;
 128    sp -= 4;
 129    cpu_stl_kernel(env, sp, retaddr);
 130    sp -= 4;
 131    cpu_stl_kernel(env, sp, fmt);
 132    env->aregs[7] = sp;
 133    /* Jump to vector.  */
 134    env->pc = cpu_ldl_kernel(env, env->vbr + vector);
 135}
 136
 137void m68k_cpu_do_interrupt(CPUState *cs)
 138{
 139    M68kCPU *cpu = M68K_CPU(cs);
 140    CPUM68KState *env = &cpu->env;
 141
 142    do_interrupt_all(env, 0);
 143}
 144
 145static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
 146{
 147    do_interrupt_all(env, 1);
 148}
 149#endif
 150
 151bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 152{
 153    M68kCPU *cpu = M68K_CPU(cs);
 154    CPUM68KState *env = &cpu->env;
 155
 156    if (interrupt_request & CPU_INTERRUPT_HARD
 157        && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) {
 158        /* Real hardware gets the interrupt vector via an IACK cycle
 159           at this point.  Current emulated hardware doesn't rely on
 160           this, so we provide/save the vector when the interrupt is
 161           first signalled.  */
 162        cs->exception_index = env->pending_vector;
 163        do_interrupt_m68k_hardirq(env);
 164        return true;
 165    }
 166    return false;
 167}
 168
 169static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
 170{
 171    CPUState *cs = CPU(m68k_env_get_cpu(env));
 172
 173    cs->exception_index = tt;
 174    cpu_loop_exit_restore(cs, raddr);
 175}
 176
 177static void raise_exception(CPUM68KState *env, int tt)
 178{
 179    raise_exception_ra(env, tt, 0);
 180}
 181
 182void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt)
 183{
 184    raise_exception(env, tt);
 185}
 186
 187void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den)
 188{
 189    uint32_t num = env->dregs[destr];
 190    uint32_t quot, rem;
 191
 192    if (den == 0) {
 193        raise_exception_ra(env, EXCP_DIV0, GETPC());
 194    }
 195    quot = num / den;
 196    rem = num % den;
 197
 198    env->cc_c = 0; /* always cleared, even if overflow */
 199    if (quot > 0xffff) {
 200        env->cc_v = -1;
 201        /* real 68040 keeps N and unset Z on overflow,
 202         * whereas documentation says "undefined"
 203         */
 204        env->cc_z = 1;
 205        return;
 206    }
 207    env->dregs[destr] = deposit32(quot, 16, 16, rem);
 208    env->cc_z = (int16_t)quot;
 209    env->cc_n = (int16_t)quot;
 210    env->cc_v = 0;
 211}
 212
 213void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den)
 214{
 215    int32_t num = env->dregs[destr];
 216    uint32_t quot, rem;
 217
 218    if (den == 0) {
 219        raise_exception_ra(env, EXCP_DIV0, GETPC());
 220    }
 221    quot = num / den;
 222    rem = num % den;
 223
 224    env->cc_c = 0; /* always cleared, even if overflow */
 225    if (quot != (int16_t)quot) {
 226        env->cc_v = -1;
 227        /* nothing else is modified */
 228        /* real 68040 keeps N and unset Z on overflow,
 229         * whereas documentation says "undefined"
 230         */
 231        env->cc_z = 1;
 232        return;
 233    }
 234    env->dregs[destr] = deposit32(quot, 16, 16, rem);
 235    env->cc_z = (int16_t)quot;
 236    env->cc_n = (int16_t)quot;
 237    env->cc_v = 0;
 238}
 239
 240void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den)
 241{
 242    uint32_t num = env->dregs[numr];
 243    uint32_t quot, rem;
 244
 245    if (den == 0) {
 246        raise_exception_ra(env, EXCP_DIV0, GETPC());
 247    }
 248    quot = num / den;
 249    rem = num % den;
 250
 251    env->cc_c = 0;
 252    env->cc_z = quot;
 253    env->cc_n = quot;
 254    env->cc_v = 0;
 255
 256    if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) {
 257        if (numr == regr) {
 258            env->dregs[numr] = quot;
 259        } else {
 260            env->dregs[regr] = rem;
 261        }
 262    } else {
 263        env->dregs[regr] = rem;
 264        env->dregs[numr] = quot;
 265    }
 266}
 267
 268void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den)
 269{
 270    int32_t num = env->dregs[numr];
 271    int32_t quot, rem;
 272
 273    if (den == 0) {
 274        raise_exception_ra(env, EXCP_DIV0, GETPC());
 275    }
 276    quot = num / den;
 277    rem = num % den;
 278
 279    env->cc_c = 0;
 280    env->cc_z = quot;
 281    env->cc_n = quot;
 282    env->cc_v = 0;
 283
 284    if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) {
 285        if (numr == regr) {
 286            env->dregs[numr] = quot;
 287        } else {
 288            env->dregs[regr] = rem;
 289        }
 290    } else {
 291        env->dregs[regr] = rem;
 292        env->dregs[numr] = quot;
 293    }
 294}
 295
 296void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den)
 297{
 298    uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
 299    uint64_t quot;
 300    uint32_t rem;
 301
 302    if (den == 0) {
 303        raise_exception_ra(env, EXCP_DIV0, GETPC());
 304    }
 305    quot = num / den;
 306    rem = num % den;
 307
 308    env->cc_c = 0; /* always cleared, even if overflow */
 309    if (quot > 0xffffffffULL) {
 310        env->cc_v = -1;
 311        /* real 68040 keeps N and unset Z on overflow,
 312         * whereas documentation says "undefined"
 313         */
 314        env->cc_z = 1;
 315        return;
 316    }
 317    env->cc_z = quot;
 318    env->cc_n = quot;
 319    env->cc_v = 0;
 320
 321    /*
 322     * If Dq and Dr are the same, the quotient is returned.
 323     * therefore we set Dq last.
 324     */
 325
 326    env->dregs[regr] = rem;
 327    env->dregs[numr] = quot;
 328}
 329
 330void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den)
 331{
 332    int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
 333    int64_t quot;
 334    int32_t rem;
 335
 336    if (den == 0) {
 337        raise_exception_ra(env, EXCP_DIV0, GETPC());
 338    }
 339    quot = num / den;
 340    rem = num % den;
 341
 342    env->cc_c = 0; /* always cleared, even if overflow */
 343    if (quot != (int32_t)quot) {
 344        env->cc_v = -1;
 345        /* real 68040 keeps N and unset Z on overflow,
 346         * whereas documentation says "undefined"
 347         */
 348        env->cc_z = 1;
 349        return;
 350    }
 351    env->cc_z = quot;
 352    env->cc_n = quot;
 353    env->cc_v = 0;
 354
 355    /*
 356     * If Dq and Dr are the same, the quotient is returned.
 357     * therefore we set Dq last.
 358     */
 359
 360    env->dregs[regr] = rem;
 361    env->dregs[numr] = quot;
 362}
 363
 364/* We're executing in a serial context -- no need to be atomic.  */
 365void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
 366{
 367    uint32_t Dc1 = extract32(regs, 9, 3);
 368    uint32_t Dc2 = extract32(regs, 6, 3);
 369    uint32_t Du1 = extract32(regs, 3, 3);
 370    uint32_t Du2 = extract32(regs, 0, 3);
 371    int16_t c1 = env->dregs[Dc1];
 372    int16_t c2 = env->dregs[Dc2];
 373    int16_t u1 = env->dregs[Du1];
 374    int16_t u2 = env->dregs[Du2];
 375    int16_t l1, l2;
 376    uintptr_t ra = GETPC();
 377
 378    l1 = cpu_lduw_data_ra(env, a1, ra);
 379    l2 = cpu_lduw_data_ra(env, a2, ra);
 380    if (l1 == c1 && l2 == c2) {
 381        cpu_stw_data_ra(env, a1, u1, ra);
 382        cpu_stw_data_ra(env, a2, u2, ra);
 383    }
 384
 385    if (c1 != l1) {
 386        env->cc_n = l1;
 387        env->cc_v = c1;
 388    } else {
 389        env->cc_n = l2;
 390        env->cc_v = c2;
 391    }
 392    env->cc_op = CC_OP_CMPW;
 393    env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1);
 394    env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2);
 395}
 396
 397static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2,
 398                     bool parallel)
 399{
 400    uint32_t Dc1 = extract32(regs, 9, 3);
 401    uint32_t Dc2 = extract32(regs, 6, 3);
 402    uint32_t Du1 = extract32(regs, 3, 3);
 403    uint32_t Du2 = extract32(regs, 0, 3);
 404    uint32_t c1 = env->dregs[Dc1];
 405    uint32_t c2 = env->dregs[Dc2];
 406    uint32_t u1 = env->dregs[Du1];
 407    uint32_t u2 = env->dregs[Du2];
 408    uint32_t l1, l2;
 409    uintptr_t ra = GETPC();
 410#if defined(CONFIG_ATOMIC64) && !defined(CONFIG_USER_ONLY)
 411    int mmu_idx = cpu_mmu_index(env, 0);
 412    TCGMemOpIdx oi;
 413#endif
 414
 415    if (parallel) {
 416        /* We're executing in a parallel context -- must be atomic.  */
 417#ifdef CONFIG_ATOMIC64
 418        uint64_t c, u, l;
 419        if ((a1 & 7) == 0 && a2 == a1 + 4) {
 420            c = deposit64(c2, 32, 32, c1);
 421            u = deposit64(u2, 32, 32, u1);
 422#ifdef CONFIG_USER_ONLY
 423            l = helper_atomic_cmpxchgq_be(env, a1, c, u);
 424#else
 425            oi = make_memop_idx(MO_BEQ, mmu_idx);
 426            l = helper_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra);
 427#endif
 428            l1 = l >> 32;
 429            l2 = l;
 430        } else if ((a2 & 7) == 0 && a1 == a2 + 4) {
 431            c = deposit64(c1, 32, 32, c2);
 432            u = deposit64(u1, 32, 32, u2);
 433#ifdef CONFIG_USER_ONLY
 434            l = helper_atomic_cmpxchgq_be(env, a2, c, u);
 435#else
 436            oi = make_memop_idx(MO_BEQ, mmu_idx);
 437            l = helper_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra);
 438#endif
 439            l2 = l >> 32;
 440            l1 = l;
 441        } else
 442#endif
 443        {
 444            /* Tell the main loop we need to serialize this insn.  */
 445            cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
 446        }
 447    } else {
 448        /* We're executing in a serial context -- no need to be atomic.  */
 449        l1 = cpu_ldl_data_ra(env, a1, ra);
 450        l2 = cpu_ldl_data_ra(env, a2, ra);
 451        if (l1 == c1 && l2 == c2) {
 452            cpu_stl_data_ra(env, a1, u1, ra);
 453            cpu_stl_data_ra(env, a2, u2, ra);
 454        }
 455    }
 456
 457    if (c1 != l1) {
 458        env->cc_n = l1;
 459        env->cc_v = c1;
 460    } else {
 461        env->cc_n = l2;
 462        env->cc_v = c2;
 463    }
 464    env->cc_op = CC_OP_CMPL;
 465    env->dregs[Dc1] = l1;
 466    env->dregs[Dc2] = l2;
 467}
 468
 469void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
 470{
 471    do_cas2l(env, regs, a1, a2, false);
 472}
 473
 474void HELPER(cas2l_parallel)(CPUM68KState *env, uint32_t regs, uint32_t a1,
 475                            uint32_t a2)
 476{
 477    do_cas2l(env, regs, a1, a2, true);
 478}
 479
 480struct bf_data {
 481    uint32_t addr;
 482    uint32_t bofs;
 483    uint32_t blen;
 484    uint32_t len;
 485};
 486
 487static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len)
 488{
 489    int bofs, blen;
 490
 491    /* Bound length; map 0 to 32.  */
 492    len = ((len - 1) & 31) + 1;
 493
 494    /* Note that ofs is signed.  */
 495    addr += ofs / 8;
 496    bofs = ofs % 8;
 497    if (bofs < 0) {
 498        bofs += 8;
 499        addr -= 1;
 500    }
 501
 502    /* Compute the number of bytes required (minus one) to
 503       satisfy the bitfield.  */
 504    blen = (bofs + len - 1) / 8;
 505
 506    /* Canonicalize the bit offset for data loaded into a 64-bit big-endian
 507       word.  For the cases where BLEN is not a power of 2, adjust ADDR so
 508       that we can use the next power of two sized load without crossing a
 509       page boundary, unless the field itself crosses the boundary.  */
 510    switch (blen) {
 511    case 0:
 512        bofs += 56;
 513        break;
 514    case 1:
 515        bofs += 48;
 516        break;
 517    case 2:
 518        if (addr & 1) {
 519            bofs += 8;
 520            addr -= 1;
 521        }
 522        /* fallthru */
 523    case 3:
 524        bofs += 32;
 525        break;
 526    case 4:
 527        if (addr & 3) {
 528            bofs += 8 * (addr & 3);
 529            addr &= -4;
 530        }
 531        break;
 532    default:
 533        g_assert_not_reached();
 534    }
 535
 536    return (struct bf_data){
 537        .addr = addr,
 538        .bofs = bofs,
 539        .blen = blen,
 540        .len = len,
 541    };
 542}
 543
 544static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen,
 545                        uintptr_t ra)
 546{
 547    switch (blen) {
 548    case 0:
 549        return cpu_ldub_data_ra(env, addr, ra);
 550    case 1:
 551        return cpu_lduw_data_ra(env, addr, ra);
 552    case 2:
 553    case 3:
 554        return cpu_ldl_data_ra(env, addr, ra);
 555    case 4:
 556        return cpu_ldq_data_ra(env, addr, ra);
 557    default:
 558        g_assert_not_reached();
 559    }
 560}
 561
 562static void bf_store(CPUM68KState *env, uint32_t addr, int blen,
 563                     uint64_t data, uintptr_t ra)
 564{
 565    switch (blen) {
 566    case 0:
 567        cpu_stb_data_ra(env, addr, data, ra);
 568        break;
 569    case 1:
 570        cpu_stw_data_ra(env, addr, data, ra);
 571        break;
 572    case 2:
 573    case 3:
 574        cpu_stl_data_ra(env, addr, data, ra);
 575        break;
 576    case 4:
 577        cpu_stq_data_ra(env, addr, data, ra);
 578        break;
 579    default:
 580        g_assert_not_reached();
 581    }
 582}
 583
 584uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr,
 585                            int32_t ofs, uint32_t len)
 586{
 587    uintptr_t ra = GETPC();
 588    struct bf_data d = bf_prep(addr, ofs, len);
 589    uint64_t data = bf_load(env, d.addr, d.blen, ra);
 590
 591    return (int64_t)(data << d.bofs) >> (64 - d.len);
 592}
 593
 594uint64_t HELPER(bfextu_mem)(CPUM68KState *env, uint32_t addr,
 595                            int32_t ofs, uint32_t len)
 596{
 597    uintptr_t ra = GETPC();
 598    struct bf_data d = bf_prep(addr, ofs, len);
 599    uint64_t data = bf_load(env, d.addr, d.blen, ra);
 600
 601    /* Put CC_N at the top of the high word; put the zero-extended value
 602       at the bottom of the low word.  */
 603    data <<= d.bofs;
 604    data >>= 64 - d.len;
 605    data |= data << (64 - d.len);
 606
 607    return data;
 608}
 609
 610uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val,
 611                           int32_t ofs, uint32_t len)
 612{
 613    uintptr_t ra = GETPC();
 614    struct bf_data d = bf_prep(addr, ofs, len);
 615    uint64_t data = bf_load(env, d.addr, d.blen, ra);
 616    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
 617
 618    data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs);
 619
 620    bf_store(env, d.addr, d.blen, data, ra);
 621
 622    /* The field at the top of the word is also CC_N for CC_OP_LOGIC.  */
 623    return val << (32 - d.len);
 624}
 625
 626uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr,
 627                           int32_t ofs, uint32_t len)
 628{
 629    uintptr_t ra = GETPC();
 630    struct bf_data d = bf_prep(addr, ofs, len);
 631    uint64_t data = bf_load(env, d.addr, d.blen, ra);
 632    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
 633
 634    bf_store(env, d.addr, d.blen, data ^ mask, ra);
 635
 636    return ((data & mask) << d.bofs) >> 32;
 637}
 638
 639uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr,
 640                           int32_t ofs, uint32_t len)
 641{
 642    uintptr_t ra = GETPC();
 643    struct bf_data d = bf_prep(addr, ofs, len);
 644    uint64_t data = bf_load(env, d.addr, d.blen, ra);
 645    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
 646
 647    bf_store(env, d.addr, d.blen, data & ~mask, ra);
 648
 649    return ((data & mask) << d.bofs) >> 32;
 650}
 651
 652uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr,
 653                           int32_t ofs, uint32_t len)
 654{
 655    uintptr_t ra = GETPC();
 656    struct bf_data d = bf_prep(addr, ofs, len);
 657    uint64_t data = bf_load(env, d.addr, d.blen, ra);
 658    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
 659
 660    bf_store(env, d.addr, d.blen, data | mask, ra);
 661
 662    return ((data & mask) << d.bofs) >> 32;
 663}
 664
 665uint32_t HELPER(bfffo_reg)(uint32_t n, uint32_t ofs, uint32_t len)
 666{
 667    return (n ? clz32(n) : len) + ofs;
 668}
 669
 670uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr,
 671                           int32_t ofs, uint32_t len)
 672{
 673    uintptr_t ra = GETPC();
 674    struct bf_data d = bf_prep(addr, ofs, len);
 675    uint64_t data = bf_load(env, d.addr, d.blen, ra);
 676    uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
 677    uint64_t n = (data & mask) << d.bofs;
 678    uint32_t ffo = helper_bfffo_reg(n >> 32, ofs, d.len);
 679
 680    /* Return FFO in the low word and N in the high word.
 681       Note that because of MASK and the shift, the low word
 682       is already zero.  */
 683    return n | ffo;
 684}
 685