qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cp0_helper.c (47257B)


      1 /*
      2  *  Helpers for emulation of CP0-related MIPS instructions.
      3  *
      4  *  Copyright (C) 2004-2005  Jocelyn Mayer
      5  *  Copyright (C) 2020  Wave Computing, Inc.
      6  *  Copyright (C) 2020  Aleksandar Markovic <amarkovic@wavecomp.com>
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Lesser General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2.1 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Lesser General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Lesser General Public
     19  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     20  *
     21  */
     22 
     23 #include "qemu/osdep.h"
     24 #include "qemu/log.h"
     25 #include "qemu/main-loop.h"
     26 #include "cpu.h"
     27 #include "internal.h"
     28 #include "qemu/host-utils.h"
     29 #include "exec/helper-proto.h"
     30 #include "exec/exec-all.h"
     31 
     32 
     33 /* SMP helpers.  */
     34 static bool mips_vpe_is_wfi(MIPSCPU *c)
     35 {
     36     CPUState *cpu = CPU(c);
     37     CPUMIPSState *env = &c->env;
     38 
     39     /*
     40      * If the VPE is halted but otherwise active, it means it's waiting for
     41      * an interrupt.\
     42      */
     43     return cpu->halted && mips_vpe_active(env);
     44 }
     45 
     46 static bool mips_vp_is_wfi(MIPSCPU *c)
     47 {
     48     CPUState *cpu = CPU(c);
     49     CPUMIPSState *env = &c->env;
     50 
     51     return cpu->halted && mips_vp_active(env);
     52 }
     53 
     54 static inline void mips_vpe_wake(MIPSCPU *c)
     55 {
     56     /*
     57      * Don't set ->halted = 0 directly, let it be done via cpu_has_work
     58      * because there might be other conditions that state that c should
     59      * be sleeping.
     60      */
     61     qemu_mutex_lock_iothread();
     62     cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
     63     qemu_mutex_unlock_iothread();
     64 }
     65 
     66 static inline void mips_vpe_sleep(MIPSCPU *cpu)
     67 {
     68     CPUState *cs = CPU(cpu);
     69 
     70     /*
     71      * The VPE was shut off, really go to bed.
     72      * Reset any old _WAKE requests.
     73      */
     74     cs->halted = 1;
     75     cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
     76 }
     77 
     78 static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
     79 {
     80     CPUMIPSState *c = &cpu->env;
     81 
     82     /* FIXME: TC reschedule.  */
     83     if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
     84         mips_vpe_wake(cpu);
     85     }
     86 }
     87 
     88 static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
     89 {
     90     CPUMIPSState *c = &cpu->env;
     91 
     92     /* FIXME: TC reschedule.  */
     93     if (!mips_vpe_active(c)) {
     94         mips_vpe_sleep(cpu);
     95     }
     96 }
     97 
     98 /**
     99  * mips_cpu_map_tc:
    100  * @env: CPU from which mapping is performed.
    101  * @tc: Should point to an int with the value of the global TC index.
    102  *
    103  * This function will transform @tc into a local index within the
    104  * returned #CPUMIPSState.
    105  */
    106 
    107 /*
    108  * FIXME: This code assumes that all VPEs have the same number of TCs,
    109  *        which depends on runtime setup. Can probably be fixed by
    110  *        walking the list of CPUMIPSStates.
    111  */
    112 static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
    113 {
    114     MIPSCPU *cpu;
    115     CPUState *cs;
    116     CPUState *other_cs;
    117     int vpe_idx;
    118     int tc_idx = *tc;
    119 
    120     if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
    121         /* Not allowed to address other CPUs.  */
    122         *tc = env->current_tc;
    123         return env;
    124     }
    125 
    126     cs = env_cpu(env);
    127     vpe_idx = tc_idx / cs->nr_threads;
    128     *tc = tc_idx % cs->nr_threads;
    129     other_cs = qemu_get_cpu(vpe_idx);
    130     if (other_cs == NULL) {
    131         return env;
    132     }
    133     cpu = MIPS_CPU(other_cs);
    134     return &cpu->env;
    135 }
    136 
    137 /*
    138  * The per VPE CP0_Status register shares some fields with the per TC
    139  * CP0_TCStatus registers. These fields are wired to the same registers,
    140  * so changes to either of them should be reflected on both registers.
    141  *
    142  * Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
    143  *
    144  * These helper call synchronizes the regs for a given cpu.
    145  */
    146 
    147 /*
    148  * Called for updates to CP0_Status.  Defined in "cpu.h" for gdbstub.c.
    149  * static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,
    150  *                                   int tc);
    151  */
    152 
    153 /* Called for updates to CP0_TCStatus.  */
    154 static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
    155                              target_ulong v)
    156 {
    157     uint32_t status;
    158     uint32_t tcu, tmx, tasid, tksu;
    159     uint32_t mask = ((1U << CP0St_CU3)
    160                        | (1 << CP0St_CU2)
    161                        | (1 << CP0St_CU1)
    162                        | (1 << CP0St_CU0)
    163                        | (1 << CP0St_MX)
    164                        | (3 << CP0St_KSU));
    165 
    166     tcu = (v >> CP0TCSt_TCU0) & 0xf;
    167     tmx = (v >> CP0TCSt_TMX) & 0x1;
    168     tasid = v & cpu->CP0_EntryHi_ASID_mask;
    169     tksu = (v >> CP0TCSt_TKSU) & 0x3;
    170 
    171     status = tcu << CP0St_CU0;
    172     status |= tmx << CP0St_MX;
    173     status |= tksu << CP0St_KSU;
    174 
    175     cpu->CP0_Status &= ~mask;
    176     cpu->CP0_Status |= status;
    177 
    178     /* Sync the TASID with EntryHi.  */
    179     cpu->CP0_EntryHi &= ~cpu->CP0_EntryHi_ASID_mask;
    180     cpu->CP0_EntryHi |= tasid;
    181 
    182     compute_hflags(cpu);
    183 }
    184 
    185 /* Called for updates to CP0_EntryHi.  */
    186 static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
    187 {
    188     int32_t *tcst;
    189     uint32_t asid, v = cpu->CP0_EntryHi;
    190 
    191     asid = v & cpu->CP0_EntryHi_ASID_mask;
    192 
    193     if (tc == cpu->current_tc) {
    194         tcst = &cpu->active_tc.CP0_TCStatus;
    195     } else {
    196         tcst = &cpu->tcs[tc].CP0_TCStatus;
    197     }
    198 
    199     *tcst &= ~cpu->CP0_EntryHi_ASID_mask;
    200     *tcst |= asid;
    201 }
    202 
    203 /* XXX: do not use a global */
    204 uint32_t cpu_mips_get_random(CPUMIPSState *env)
    205 {
    206     static uint32_t seed = 1;
    207     static uint32_t prev_idx;
    208     uint32_t idx;
    209     uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
    210 
    211     if (nb_rand_tlb == 1) {
    212         return env->tlb->nb_tlb - 1;
    213     }
    214 
    215     /* Don't return same value twice, so get another value */
    216     do {
    217         /*
    218          * Use a simple algorithm of Linear Congruential Generator
    219          * from ISO/IEC 9899 standard.
    220          */
    221         seed = 1103515245 * seed + 12345;
    222         idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired;
    223     } while (idx == prev_idx);
    224     prev_idx = idx;
    225     return idx;
    226 }
    227 
    228 /* CP0 helpers */
    229 target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
    230 {
    231     return env->mvp->CP0_MVPControl;
    232 }
    233 
    234 target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
    235 {
    236     return env->mvp->CP0_MVPConf0;
    237 }
    238 
    239 target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
    240 {
    241     return env->mvp->CP0_MVPConf1;
    242 }
    243 
    244 target_ulong helper_mfc0_random(CPUMIPSState *env)
    245 {
    246     return (int32_t)cpu_mips_get_random(env);
    247 }
    248 
    249 target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
    250 {
    251     return env->active_tc.CP0_TCStatus;
    252 }
    253 
    254 target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
    255 {
    256     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    257     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    258 
    259     if (other_tc == other->current_tc) {
    260         return other->active_tc.CP0_TCStatus;
    261     } else {
    262         return other->tcs[other_tc].CP0_TCStatus;
    263     }
    264 }
    265 
    266 target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
    267 {
    268     return env->active_tc.CP0_TCBind;
    269 }
    270 
    271 target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
    272 {
    273     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    274     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    275 
    276     if (other_tc == other->current_tc) {
    277         return other->active_tc.CP0_TCBind;
    278     } else {
    279         return other->tcs[other_tc].CP0_TCBind;
    280     }
    281 }
    282 
    283 target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
    284 {
    285     return env->active_tc.PC;
    286 }
    287 
    288 target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
    289 {
    290     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    291     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    292 
    293     if (other_tc == other->current_tc) {
    294         return other->active_tc.PC;
    295     } else {
    296         return other->tcs[other_tc].PC;
    297     }
    298 }
    299 
    300 target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
    301 {
    302     return env->active_tc.CP0_TCHalt;
    303 }
    304 
    305 target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
    306 {
    307     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    308     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    309 
    310     if (other_tc == other->current_tc) {
    311         return other->active_tc.CP0_TCHalt;
    312     } else {
    313         return other->tcs[other_tc].CP0_TCHalt;
    314     }
    315 }
    316 
    317 target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
    318 {
    319     return env->active_tc.CP0_TCContext;
    320 }
    321 
    322 target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
    323 {
    324     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    325     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    326 
    327     if (other_tc == other->current_tc) {
    328         return other->active_tc.CP0_TCContext;
    329     } else {
    330         return other->tcs[other_tc].CP0_TCContext;
    331     }
    332 }
    333 
    334 target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
    335 {
    336     return env->active_tc.CP0_TCSchedule;
    337 }
    338 
    339 target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
    340 {
    341     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    342     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    343 
    344     if (other_tc == other->current_tc) {
    345         return other->active_tc.CP0_TCSchedule;
    346     } else {
    347         return other->tcs[other_tc].CP0_TCSchedule;
    348     }
    349 }
    350 
    351 target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
    352 {
    353     return env->active_tc.CP0_TCScheFBack;
    354 }
    355 
    356 target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
    357 {
    358     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    359     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    360 
    361     if (other_tc == other->current_tc) {
    362         return other->active_tc.CP0_TCScheFBack;
    363     } else {
    364         return other->tcs[other_tc].CP0_TCScheFBack;
    365     }
    366 }
    367 
    368 target_ulong helper_mfc0_count(CPUMIPSState *env)
    369 {
    370     return (int32_t)cpu_mips_get_count(env);
    371 }
    372 
    373 target_ulong helper_mfc0_saar(CPUMIPSState *env)
    374 {
    375     if ((env->CP0_SAARI & 0x3f) < 2) {
    376         return (int32_t) env->CP0_SAAR[env->CP0_SAARI & 0x3f];
    377     }
    378     return 0;
    379 }
    380 
    381 target_ulong helper_mfhc0_saar(CPUMIPSState *env)
    382 {
    383     if ((env->CP0_SAARI & 0x3f) < 2) {
    384         return env->CP0_SAAR[env->CP0_SAARI & 0x3f] >> 32;
    385     }
    386     return 0;
    387 }
    388 
    389 target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
    390 {
    391     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    392     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    393 
    394     return other->CP0_EntryHi;
    395 }
    396 
    397 target_ulong helper_mftc0_cause(CPUMIPSState *env)
    398 {
    399     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    400     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    401 
    402     return other->CP0_Cause;
    403 }
    404 
    405 target_ulong helper_mftc0_status(CPUMIPSState *env)
    406 {
    407     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    408     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    409 
    410     return other->CP0_Status;
    411 }
    412 
    413 target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
    414 {
    415     return (int32_t)(env->CP0_LLAddr >> env->CP0_LLAddr_shift);
    416 }
    417 
    418 target_ulong helper_mfc0_maar(CPUMIPSState *env)
    419 {
    420     return (int32_t) env->CP0_MAAR[env->CP0_MAARI];
    421 }
    422 
    423 target_ulong helper_mfhc0_maar(CPUMIPSState *env)
    424 {
    425     return env->CP0_MAAR[env->CP0_MAARI] >> 32;
    426 }
    427 
    428 target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
    429 {
    430     return (int32_t)env->CP0_WatchLo[sel];
    431 }
    432 
    433 target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
    434 {
    435     return (int32_t) env->CP0_WatchHi[sel];
    436 }
    437 
    438 target_ulong helper_mfhc0_watchhi(CPUMIPSState *env, uint32_t sel)
    439 {
    440     return env->CP0_WatchHi[sel] >> 32;
    441 }
    442 
    443 target_ulong helper_mfc0_debug(CPUMIPSState *env)
    444 {
    445     target_ulong t0 = env->CP0_Debug;
    446     if (env->hflags & MIPS_HFLAG_DM) {
    447         t0 |= 1 << CP0DB_DM;
    448     }
    449 
    450     return t0;
    451 }
    452 
    453 target_ulong helper_mftc0_debug(CPUMIPSState *env)
    454 {
    455     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    456     int32_t tcstatus;
    457     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    458 
    459     if (other_tc == other->current_tc) {
    460         tcstatus = other->active_tc.CP0_Debug_tcstatus;
    461     } else {
    462         tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
    463     }
    464 
    465     /* XXX: Might be wrong, check with EJTAG spec. */
    466     return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
    467             (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
    468 }
    469 
    470 #if defined(TARGET_MIPS64)
    471 target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
    472 {
    473     return env->active_tc.PC;
    474 }
    475 
    476 target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
    477 {
    478     return env->active_tc.CP0_TCHalt;
    479 }
    480 
    481 target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
    482 {
    483     return env->active_tc.CP0_TCContext;
    484 }
    485 
    486 target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
    487 {
    488     return env->active_tc.CP0_TCSchedule;
    489 }
    490 
    491 target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
    492 {
    493     return env->active_tc.CP0_TCScheFBack;
    494 }
    495 
    496 target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
    497 {
    498     return env->CP0_LLAddr >> env->CP0_LLAddr_shift;
    499 }
    500 
    501 target_ulong helper_dmfc0_maar(CPUMIPSState *env)
    502 {
    503     return env->CP0_MAAR[env->CP0_MAARI];
    504 }
    505 
    506 target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
    507 {
    508     return env->CP0_WatchLo[sel];
    509 }
    510 
    511 target_ulong helper_dmfc0_watchhi(CPUMIPSState *env, uint32_t sel)
    512 {
    513     return env->CP0_WatchHi[sel];
    514 }
    515 
    516 target_ulong helper_dmfc0_saar(CPUMIPSState *env)
    517 {
    518     if ((env->CP0_SAARI & 0x3f) < 2) {
    519         return env->CP0_SAAR[env->CP0_SAARI & 0x3f];
    520     }
    521     return 0;
    522 }
    523 #endif /* TARGET_MIPS64 */
    524 
    525 void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
    526 {
    527     uint32_t index_p = env->CP0_Index & 0x80000000;
    528     uint32_t tlb_index = arg1 & 0x7fffffff;
    529     if (tlb_index < env->tlb->nb_tlb) {
    530         if (env->insn_flags & ISA_MIPS_R6) {
    531             index_p |= arg1 & 0x80000000;
    532         }
    533         env->CP0_Index = index_p | tlb_index;
    534     }
    535 }
    536 
    537 void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
    538 {
    539     uint32_t mask = 0;
    540     uint32_t newval;
    541 
    542     if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
    543         mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
    544                 (1 << CP0MVPCo_EVP);
    545     }
    546     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) {
    547         mask |= (1 << CP0MVPCo_STLB);
    548     }
    549     newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
    550 
    551     /* TODO: Enable/disable shared TLB, enable/disable VPEs. */
    552 
    553     env->mvp->CP0_MVPControl = newval;
    554 }
    555 
    556 void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
    557 {
    558     uint32_t mask;
    559     uint32_t newval;
    560 
    561     mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
    562            (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
    563     newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
    564 
    565     /*
    566      * Yield scheduler intercept not implemented.
    567      * Gating storage scheduler intercept not implemented.
    568      */
    569 
    570     /* TODO: Enable/disable TCs. */
    571 
    572     env->CP0_VPEControl = newval;
    573 }
    574 
    575 void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
    576 {
    577     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    578     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    579     uint32_t mask;
    580     uint32_t newval;
    581 
    582     mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
    583            (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
    584     newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
    585 
    586     /* TODO: Enable/disable TCs.  */
    587 
    588     other->CP0_VPEControl = newval;
    589 }
    590 
    591 target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
    592 {
    593     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    594     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    595     /* FIXME: Mask away return zero on read bits.  */
    596     return other->CP0_VPEControl;
    597 }
    598 
    599 target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
    600 {
    601     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    602     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    603 
    604     return other->CP0_VPEConf0;
    605 }
    606 
    607 void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
    608 {
    609     uint32_t mask = 0;
    610     uint32_t newval;
    611 
    612     if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
    613         if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) {
    614             mask |= (0xff << CP0VPEC0_XTC);
    615         }
    616         mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
    617     }
    618     newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
    619 
    620     /* TODO: TC exclusive handling due to ERL/EXL. */
    621 
    622     env->CP0_VPEConf0 = newval;
    623 }
    624 
    625 void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
    626 {
    627     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    628     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    629     uint32_t mask = 0;
    630     uint32_t newval;
    631 
    632     mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
    633     newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
    634 
    635     /* TODO: TC exclusive handling due to ERL/EXL.  */
    636     other->CP0_VPEConf0 = newval;
    637 }
    638 
    639 void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
    640 {
    641     uint32_t mask = 0;
    642     uint32_t newval;
    643 
    644     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
    645         mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
    646                 (0xff << CP0VPEC1_NCP1);
    647     newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
    648 
    649     /* UDI not implemented. */
    650     /* CP2 not implemented. */
    651 
    652     /* TODO: Handle FPU (CP1) binding. */
    653 
    654     env->CP0_VPEConf1 = newval;
    655 }
    656 
    657 void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
    658 {
    659     /* Yield qualifier inputs not implemented. */
    660     env->CP0_YQMask = 0x00000000;
    661 }
    662 
    663 void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
    664 {
    665     env->CP0_VPEOpt = arg1 & 0x0000ffff;
    666 }
    667 
    668 #define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
    669 
    670 void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
    671 {
    672     /* 1k pages not implemented */
    673     target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
    674     env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
    675                         | (rxi << (CP0EnLo_XI - 30));
    676 }
    677 
    678 #if defined(TARGET_MIPS64)
    679 #define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
    680 
    681 void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
    682 {
    683     uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
    684     env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
    685 }
    686 #endif
    687 
    688 void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
    689 {
    690     uint32_t mask = env->CP0_TCStatus_rw_bitmask;
    691     uint32_t newval;
    692 
    693     newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
    694 
    695     env->active_tc.CP0_TCStatus = newval;
    696     sync_c0_tcstatus(env, env->current_tc, newval);
    697 }
    698 
    699 void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
    700 {
    701     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    702     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    703 
    704     if (other_tc == other->current_tc) {
    705         other->active_tc.CP0_TCStatus = arg1;
    706     } else {
    707         other->tcs[other_tc].CP0_TCStatus = arg1;
    708     }
    709     sync_c0_tcstatus(other, other_tc, arg1);
    710 }
    711 
    712 void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
    713 {
    714     uint32_t mask = (1 << CP0TCBd_TBE);
    715     uint32_t newval;
    716 
    717     if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) {
    718         mask |= (1 << CP0TCBd_CurVPE);
    719     }
    720     newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
    721     env->active_tc.CP0_TCBind = newval;
    722 }
    723 
    724 void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
    725 {
    726     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    727     uint32_t mask = (1 << CP0TCBd_TBE);
    728     uint32_t newval;
    729     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    730 
    731     if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) {
    732         mask |= (1 << CP0TCBd_CurVPE);
    733     }
    734     if (other_tc == other->current_tc) {
    735         newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
    736         other->active_tc.CP0_TCBind = newval;
    737     } else {
    738         newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
    739         other->tcs[other_tc].CP0_TCBind = newval;
    740     }
    741 }
    742 
    743 void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
    744 {
    745     env->active_tc.PC = arg1;
    746     env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
    747     env->CP0_LLAddr = 0;
    748     env->lladdr = 0;
    749     /* MIPS16 not implemented. */
    750 }
    751 
    752 void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
    753 {
    754     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    755     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    756 
    757     if (other_tc == other->current_tc) {
    758         other->active_tc.PC = arg1;
    759         other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
    760         other->CP0_LLAddr = 0;
    761         other->lladdr = 0;
    762         /* MIPS16 not implemented. */
    763     } else {
    764         other->tcs[other_tc].PC = arg1;
    765         other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
    766         other->CP0_LLAddr = 0;
    767         other->lladdr = 0;
    768         /* MIPS16 not implemented. */
    769     }
    770 }
    771 
    772 void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
    773 {
    774     MIPSCPU *cpu = env_archcpu(env);
    775 
    776     env->active_tc.CP0_TCHalt = arg1 & 0x1;
    777 
    778     /* TODO: Halt TC / Restart (if allocated+active) TC. */
    779     if (env->active_tc.CP0_TCHalt & 1) {
    780         mips_tc_sleep(cpu, env->current_tc);
    781     } else {
    782         mips_tc_wake(cpu, env->current_tc);
    783     }
    784 }
    785 
    786 void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
    787 {
    788     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    789     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    790     MIPSCPU *other_cpu = env_archcpu(other);
    791 
    792     /* TODO: Halt TC / Restart (if allocated+active) TC. */
    793 
    794     if (other_tc == other->current_tc) {
    795         other->active_tc.CP0_TCHalt = arg1;
    796     } else {
    797         other->tcs[other_tc].CP0_TCHalt = arg1;
    798     }
    799 
    800     if (arg1 & 1) {
    801         mips_tc_sleep(other_cpu, other_tc);
    802     } else {
    803         mips_tc_wake(other_cpu, other_tc);
    804     }
    805 }
    806 
    807 void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
    808 {
    809     env->active_tc.CP0_TCContext = arg1;
    810 }
    811 
    812 void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
    813 {
    814     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    815     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    816 
    817     if (other_tc == other->current_tc) {
    818         other->active_tc.CP0_TCContext = arg1;
    819     } else {
    820         other->tcs[other_tc].CP0_TCContext = arg1;
    821     }
    822 }
    823 
    824 void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
    825 {
    826     env->active_tc.CP0_TCSchedule = arg1;
    827 }
    828 
    829 void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
    830 {
    831     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    832     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    833 
    834     if (other_tc == other->current_tc) {
    835         other->active_tc.CP0_TCSchedule = arg1;
    836     } else {
    837         other->tcs[other_tc].CP0_TCSchedule = arg1;
    838     }
    839 }
    840 
    841 void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
    842 {
    843     env->active_tc.CP0_TCScheFBack = arg1;
    844 }
    845 
    846 void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
    847 {
    848     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
    849     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
    850 
    851     if (other_tc == other->current_tc) {
    852         other->active_tc.CP0_TCScheFBack = arg1;
    853     } else {
    854         other->tcs[other_tc].CP0_TCScheFBack = arg1;
    855     }
    856 }
    857 
    858 void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
    859 {
    860     /* 1k pages not implemented */
    861     target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
    862     env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
    863                         | (rxi << (CP0EnLo_XI - 30));
    864 }
    865 
    866 #if defined(TARGET_MIPS64)
    867 void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
    868 {
    869     uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
    870     env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
    871 }
    872 #endif
    873 
    874 void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
    875 {
    876     env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
    877 }
    878 
    879 void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1)
    880 {
    881     int32_t old;
    882     old = env->CP0_MemoryMapID;
    883     env->CP0_MemoryMapID = (int32_t) arg1;
    884     /* If the MemoryMapID changes, flush qemu's TLB.  */
    885     if (old != env->CP0_MemoryMapID) {
    886         cpu_mips_tlb_flush(env);
    887     }
    888 }
    889 
    890 void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask)
    891 {
    892     uint32_t mask;
    893     int maskbits;
    894 
    895     /* Don't care MASKX as we don't support 1KB page */
    896     mask = extract32((uint32_t)arg1, CP0PM_MASK, 16);
    897     maskbits = cto32(mask);
    898 
    899     /* Ensure no more set bit after first zero */
    900     if ((mask >> maskbits) != 0) {
    901         goto invalid;
    902     }
    903     /* We don't support VTLB entry smaller than target page */
    904     if ((maskbits + TARGET_PAGE_BITS_MIN) < TARGET_PAGE_BITS) {
    905         goto invalid;
    906     }
    907     env->CP0_PageMask = mask << CP0PM_MASK;
    908 
    909     return;
    910 
    911 invalid:
    912     /* When invalid, set to default target page size. */
    913     mask = (~TARGET_PAGE_MASK >> TARGET_PAGE_BITS_MIN);
    914     env->CP0_PageMask = mask << CP0PM_MASK;
    915 }
    916 
    917 void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
    918 {
    919     update_pagemask(env, arg1, &env->CP0_PageMask);
    920 }
    921 
    922 void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
    923 {
    924     /* SmartMIPS not implemented */
    925     /* 1k pages not implemented */
    926     env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
    927                          (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
    928     compute_hflags(env);
    929     restore_pamask(env);
    930 }
    931 
    932 void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1)
    933 {
    934     CPUState *cs = env_cpu(env);
    935 
    936     env->CP0_SegCtl0 = arg1 & CP0SC0_MASK;
    937     tlb_flush(cs);
    938 }
    939 
    940 void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1)
    941 {
    942     CPUState *cs = env_cpu(env);
    943 
    944     env->CP0_SegCtl1 = arg1 & CP0SC1_MASK;
    945     tlb_flush(cs);
    946 }
    947 
    948 void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1)
    949 {
    950     CPUState *cs = env_cpu(env);
    951 
    952     env->CP0_SegCtl2 = arg1 & CP0SC2_MASK;
    953     tlb_flush(cs);
    954 }
    955 
    956 void helper_mtc0_pwfield(CPUMIPSState *env, target_ulong arg1)
    957 {
    958 #if defined(TARGET_MIPS64)
    959     uint64_t mask = 0x3F3FFFFFFFULL;
    960     uint32_t old_ptei = (env->CP0_PWField >> CP0PF_PTEI) & 0x3FULL;
    961     uint32_t new_ptei = (arg1 >> CP0PF_PTEI) & 0x3FULL;
    962 
    963     if ((env->insn_flags & ISA_MIPS_R6)) {
    964         if (((arg1 >> CP0PF_BDI) & 0x3FULL) < 12) {
    965             mask &= ~(0x3FULL << CP0PF_BDI);
    966         }
    967         if (((arg1 >> CP0PF_GDI) & 0x3FULL) < 12) {
    968             mask &= ~(0x3FULL << CP0PF_GDI);
    969         }
    970         if (((arg1 >> CP0PF_UDI) & 0x3FULL) < 12) {
    971             mask &= ~(0x3FULL << CP0PF_UDI);
    972         }
    973         if (((arg1 >> CP0PF_MDI) & 0x3FULL) < 12) {
    974             mask &= ~(0x3FULL << CP0PF_MDI);
    975         }
    976         if (((arg1 >> CP0PF_PTI) & 0x3FULL) < 12) {
    977             mask &= ~(0x3FULL << CP0PF_PTI);
    978         }
    979     }
    980     env->CP0_PWField = arg1 & mask;
    981 
    982     if ((new_ptei >= 32) ||
    983             ((env->insn_flags & ISA_MIPS_R6) &&
    984                     (new_ptei == 0 || new_ptei == 1))) {
    985         env->CP0_PWField = (env->CP0_PWField & ~0x3FULL) |
    986                 (old_ptei << CP0PF_PTEI);
    987     }
    988 #else
    989     uint32_t mask = 0x3FFFFFFF;
    990     uint32_t old_ptew = (env->CP0_PWField >> CP0PF_PTEW) & 0x3F;
    991     uint32_t new_ptew = (arg1 >> CP0PF_PTEW) & 0x3F;
    992 
    993     if ((env->insn_flags & ISA_MIPS_R6)) {
    994         if (((arg1 >> CP0PF_GDW) & 0x3F) < 12) {
    995             mask &= ~(0x3F << CP0PF_GDW);
    996         }
    997         if (((arg1 >> CP0PF_UDW) & 0x3F) < 12) {
    998             mask &= ~(0x3F << CP0PF_UDW);
    999         }
   1000         if (((arg1 >> CP0PF_MDW) & 0x3F) < 12) {
   1001             mask &= ~(0x3F << CP0PF_MDW);
   1002         }
   1003         if (((arg1 >> CP0PF_PTW) & 0x3F) < 12) {
   1004             mask &= ~(0x3F << CP0PF_PTW);
   1005         }
   1006     }
   1007     env->CP0_PWField = arg1 & mask;
   1008 
   1009     if ((new_ptew >= 32) ||
   1010             ((env->insn_flags & ISA_MIPS_R6) &&
   1011                     (new_ptew == 0 || new_ptew == 1))) {
   1012         env->CP0_PWField = (env->CP0_PWField & ~0x3F) |
   1013                 (old_ptew << CP0PF_PTEW);
   1014     }
   1015 #endif
   1016 }
   1017 
   1018 void helper_mtc0_pwsize(CPUMIPSState *env, target_ulong arg1)
   1019 {
   1020 #if defined(TARGET_MIPS64)
   1021     env->CP0_PWSize = arg1 & 0x3F7FFFFFFFULL;
   1022 #else
   1023     env->CP0_PWSize = arg1 & 0x3FFFFFFF;
   1024 #endif
   1025 }
   1026 
   1027 void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
   1028 {
   1029     if (env->insn_flags & ISA_MIPS_R6) {
   1030         if (arg1 < env->tlb->nb_tlb) {
   1031             env->CP0_Wired = arg1;
   1032         }
   1033     } else {
   1034         env->CP0_Wired = arg1 % env->tlb->nb_tlb;
   1035     }
   1036 }
   1037 
   1038 void helper_mtc0_pwctl(CPUMIPSState *env, target_ulong arg1)
   1039 {
   1040 #if defined(TARGET_MIPS64)
   1041     /* PWEn = 0. Hardware page table walking is not implemented. */
   1042     env->CP0_PWCtl = (env->CP0_PWCtl & 0x000000C0) | (arg1 & 0x5C00003F);
   1043 #else
   1044     env->CP0_PWCtl = (arg1 & 0x800000FF);
   1045 #endif
   1046 }
   1047 
   1048 void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
   1049 {
   1050     env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
   1051 }
   1052 
   1053 void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
   1054 {
   1055     env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
   1056 }
   1057 
   1058 void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
   1059 {
   1060     env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
   1061 }
   1062 
   1063 void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
   1064 {
   1065     env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
   1066 }
   1067 
   1068 void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
   1069 {
   1070     env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
   1071 }
   1072 
   1073 void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
   1074 {
   1075     uint32_t mask = 0x0000000F;
   1076 
   1077     if ((env->CP0_Config1 & (1 << CP0C1_PC)) &&
   1078         (env->insn_flags & ISA_MIPS_R6)) {
   1079         mask |= (1 << 4);
   1080     }
   1081     if (env->insn_flags & ISA_MIPS_R6) {
   1082         mask |= (1 << 5);
   1083     }
   1084     if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
   1085         mask |= (1 << 29);
   1086 
   1087         if (arg1 & (1 << 29)) {
   1088             env->hflags |= MIPS_HFLAG_HWRENA_ULR;
   1089         } else {
   1090             env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
   1091         }
   1092     }
   1093 
   1094     env->CP0_HWREna = arg1 & mask;
   1095 }
   1096 
   1097 void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
   1098 {
   1099     cpu_mips_store_count(env, arg1);
   1100 }
   1101 
   1102 void helper_mtc0_saari(CPUMIPSState *env, target_ulong arg1)
   1103 {
   1104     uint32_t target = arg1 & 0x3f;
   1105     if (target <= 1) {
   1106         env->CP0_SAARI = target;
   1107     }
   1108 }
   1109 
   1110 void helper_mtc0_saar(CPUMIPSState *env, target_ulong arg1)
   1111 {
   1112     uint32_t target = env->CP0_SAARI & 0x3f;
   1113     if (target < 2) {
   1114         env->CP0_SAAR[target] = arg1 & 0x00000ffffffff03fULL;
   1115         switch (target) {
   1116         case 0:
   1117             if (env->itu) {
   1118                 itc_reconfigure(env->itu);
   1119             }
   1120             break;
   1121         }
   1122     }
   1123 }
   1124 
   1125 void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1)
   1126 {
   1127     uint32_t target = env->CP0_SAARI & 0x3f;
   1128     if (target < 2) {
   1129         env->CP0_SAAR[target] =
   1130             (((uint64_t) arg1 << 32) & 0x00000fff00000000ULL) |
   1131             (env->CP0_SAAR[target] & 0x00000000ffffffffULL);
   1132         switch (target) {
   1133         case 0:
   1134             if (env->itu) {
   1135                 itc_reconfigure(env->itu);
   1136             }
   1137             break;
   1138         }
   1139     }
   1140 }
   1141 
   1142 void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
   1143 {
   1144     target_ulong old, val, mask;
   1145     mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask;
   1146     if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
   1147         mask |= 1 << CP0EnHi_EHINV;
   1148     }
   1149 
   1150     /* 1k pages not implemented */
   1151 #if defined(TARGET_MIPS64)
   1152     if (env->insn_flags & ISA_MIPS_R6) {
   1153         int entryhi_r = extract64(arg1, 62, 2);
   1154         int config0_at = extract32(env->CP0_Config0, 13, 2);
   1155         bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
   1156         if ((entryhi_r == 2) ||
   1157             (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
   1158             /* skip EntryHi.R field if new value is reserved */
   1159             mask &= ~(0x3ull << 62);
   1160         }
   1161     }
   1162     mask &= env->SEGMask;
   1163 #endif
   1164     old = env->CP0_EntryHi;
   1165     val = (arg1 & mask) | (old & ~mask);
   1166     env->CP0_EntryHi = val;
   1167     if (ase_mt_available(env)) {
   1168         sync_c0_entryhi(env, env->current_tc);
   1169     }
   1170     /* If the ASID changes, flush qemu's TLB.  */
   1171     if ((old & env->CP0_EntryHi_ASID_mask) !=
   1172         (val & env->CP0_EntryHi_ASID_mask)) {
   1173         tlb_flush(env_cpu(env));
   1174     }
   1175 }
   1176 
   1177 void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
   1178 {
   1179     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1180     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1181 
   1182     other->CP0_EntryHi = arg1;
   1183     sync_c0_entryhi(other, other_tc);
   1184 }
   1185 
   1186 void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
   1187 {
   1188     cpu_mips_store_compare(env, arg1);
   1189 }
   1190 
   1191 void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
   1192 {
   1193     uint32_t val, old;
   1194 
   1195     old = env->CP0_Status;
   1196     cpu_mips_store_status(env, arg1);
   1197     val = env->CP0_Status;
   1198 
   1199     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
   1200         qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
   1201                 old, old & env->CP0_Cause & CP0Ca_IP_mask,
   1202                 val, val & env->CP0_Cause & CP0Ca_IP_mask,
   1203                 env->CP0_Cause);
   1204         switch (cpu_mmu_index(env, false)) {
   1205         case 3:
   1206             qemu_log(", ERL\n");
   1207             break;
   1208         case MIPS_HFLAG_UM:
   1209             qemu_log(", UM\n");
   1210             break;
   1211         case MIPS_HFLAG_SM:
   1212             qemu_log(", SM\n");
   1213             break;
   1214         case MIPS_HFLAG_KM:
   1215             qemu_log("\n");
   1216             break;
   1217         default:
   1218             cpu_abort(env_cpu(env), "Invalid MMU mode!\n");
   1219             break;
   1220         }
   1221     }
   1222 }
   1223 
   1224 void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
   1225 {
   1226     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1227     uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
   1228     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1229 
   1230     other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
   1231     sync_c0_status(env, other, other_tc);
   1232 }
   1233 
   1234 void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
   1235 {
   1236     env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
   1237 }
   1238 
   1239 void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
   1240 {
   1241     uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
   1242     env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
   1243 }
   1244 
   1245 void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
   1246 {
   1247     cpu_mips_store_cause(env, arg1);
   1248 }
   1249 
   1250 void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
   1251 {
   1252     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1253     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1254 
   1255     cpu_mips_store_cause(other, arg1);
   1256 }
   1257 
   1258 target_ulong helper_mftc0_epc(CPUMIPSState *env)
   1259 {
   1260     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1261     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1262 
   1263     return other->CP0_EPC;
   1264 }
   1265 
   1266 target_ulong helper_mftc0_ebase(CPUMIPSState *env)
   1267 {
   1268     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1269     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1270 
   1271     return other->CP0_EBase;
   1272 }
   1273 
   1274 void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
   1275 {
   1276     target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
   1277     if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
   1278         mask |= ~0x3FFFFFFF;
   1279     }
   1280     env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask);
   1281 }
   1282 
   1283 void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
   1284 {
   1285     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1286     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1287     target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
   1288     if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
   1289         mask |= ~0x3FFFFFFF;
   1290     }
   1291     other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask);
   1292 }
   1293 
   1294 target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
   1295 {
   1296     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1297     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1298 
   1299     switch (idx) {
   1300     case 0: return other->CP0_Config0;
   1301     case 1: return other->CP0_Config1;
   1302     case 2: return other->CP0_Config2;
   1303     case 3: return other->CP0_Config3;
   1304     /* 4 and 5 are reserved.  */
   1305     case 6: return other->CP0_Config6;
   1306     case 7: return other->CP0_Config7;
   1307     default:
   1308         break;
   1309     }
   1310     return 0;
   1311 }
   1312 
   1313 void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
   1314 {
   1315     env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
   1316 }
   1317 
   1318 void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
   1319 {
   1320     /* tertiary/secondary caches not implemented */
   1321     env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
   1322 }
   1323 
   1324 void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
   1325 {
   1326     if (env->insn_flags & ASE_MICROMIPS) {
   1327         env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
   1328                            (arg1 & (1 << CP0C3_ISA_ON_EXC));
   1329     }
   1330 }
   1331 
   1332 void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
   1333 {
   1334     env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
   1335                        (arg1 & env->CP0_Config4_rw_bitmask);
   1336 }
   1337 
   1338 void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
   1339 {
   1340     env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
   1341                        (arg1 & env->CP0_Config5_rw_bitmask);
   1342     env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ?
   1343             0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff;
   1344     compute_hflags(env);
   1345 }
   1346 
   1347 void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
   1348 {
   1349     target_long mask = env->CP0_LLAddr_rw_bitmask;
   1350     arg1 = arg1 << env->CP0_LLAddr_shift;
   1351     env->CP0_LLAddr = (env->CP0_LLAddr & ~mask) | (arg1 & mask);
   1352 }
   1353 
   1354 #define MTC0_MAAR_MASK(env) \
   1355         ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3)
   1356 
   1357 void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1)
   1358 {
   1359     env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env);
   1360 }
   1361 
   1362 void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1)
   1363 {
   1364     env->CP0_MAAR[env->CP0_MAARI] =
   1365         (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) |
   1366         (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL);
   1367 }
   1368 
   1369 void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1)
   1370 {
   1371     int index = arg1 & 0x3f;
   1372     if (index == 0x3f) {
   1373         /*
   1374          * Software may write all ones to INDEX to determine the
   1375          *  maximum value supported.
   1376          */
   1377         env->CP0_MAARI = MIPS_MAAR_MAX - 1;
   1378     } else if (index < MIPS_MAAR_MAX) {
   1379         env->CP0_MAARI = index;
   1380     }
   1381     /*
   1382      * Other than the all ones, if the value written is not supported,
   1383      * then INDEX is unchanged from its previous value.
   1384      */
   1385 }
   1386 
   1387 void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
   1388 {
   1389     /*
   1390      * Watch exceptions for instructions, data loads, data stores
   1391      * not implemented.
   1392      */
   1393     env->CP0_WatchLo[sel] = (arg1 & ~0x7);
   1394 }
   1395 
   1396 void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
   1397 {
   1398     uint64_t mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID);
   1399     uint64_t m_bit = env->CP0_WatchHi[sel] & (1 << CP0WH_M); /* read-only */
   1400     if ((env->CP0_Config5 >> CP0C5_MI) & 1) {
   1401         mask |= 0xFFFFFFFF00000000ULL; /* MMID */
   1402     }
   1403     env->CP0_WatchHi[sel] = m_bit | (arg1 & mask);
   1404     env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
   1405 }
   1406 
   1407 void helper_mthc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
   1408 {
   1409     env->CP0_WatchHi[sel] = ((uint64_t) (arg1) << 32) |
   1410                             (env->CP0_WatchHi[sel] & 0x00000000ffffffffULL);
   1411 }
   1412 
   1413 void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
   1414 {
   1415     target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
   1416     env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
   1417 }
   1418 
   1419 void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
   1420 {
   1421     env->CP0_Framemask = arg1; /* XXX */
   1422 }
   1423 
   1424 void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
   1425 {
   1426     env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
   1427     if (arg1 & (1 << CP0DB_DM)) {
   1428         env->hflags |= MIPS_HFLAG_DM;
   1429     } else {
   1430         env->hflags &= ~MIPS_HFLAG_DM;
   1431     }
   1432 }
   1433 
   1434 void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
   1435 {
   1436     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1437     uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
   1438     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1439 
   1440     /* XXX: Might be wrong, check with EJTAG spec. */
   1441     if (other_tc == other->current_tc) {
   1442         other->active_tc.CP0_Debug_tcstatus = val;
   1443     } else {
   1444         other->tcs[other_tc].CP0_Debug_tcstatus = val;
   1445     }
   1446     other->CP0_Debug = (other->CP0_Debug &
   1447                      ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
   1448                      (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
   1449 }
   1450 
   1451 void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
   1452 {
   1453     env->CP0_Performance0 = arg1 & 0x000007ff;
   1454 }
   1455 
   1456 void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
   1457 {
   1458     int32_t wst = arg1 & (1 << CP0EC_WST);
   1459     int32_t spr = arg1 & (1 << CP0EC_SPR);
   1460     int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
   1461 
   1462     env->CP0_ErrCtl = wst | spr | itc;
   1463 
   1464     if (itc && !wst && !spr) {
   1465         env->hflags |= MIPS_HFLAG_ITC_CACHE;
   1466     } else {
   1467         env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
   1468     }
   1469 }
   1470 
   1471 void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
   1472 {
   1473     if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
   1474         /*
   1475          * If CACHE instruction is configured for ITC tags then make all
   1476          * CP0.TagLo bits writable. The actual write to ITC Configuration
   1477          * Tag will take care of the read-only bits.
   1478          */
   1479         env->CP0_TagLo = arg1;
   1480     } else {
   1481         env->CP0_TagLo = arg1 & 0xFFFFFCF6;
   1482     }
   1483 }
   1484 
   1485 void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
   1486 {
   1487     env->CP0_DataLo = arg1; /* XXX */
   1488 }
   1489 
   1490 void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
   1491 {
   1492     env->CP0_TagHi = arg1; /* XXX */
   1493 }
   1494 
   1495 void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
   1496 {
   1497     env->CP0_DataHi = arg1; /* XXX */
   1498 }
   1499 
   1500 /* MIPS MT functions */
   1501 target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
   1502 {
   1503     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1504     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1505 
   1506     if (other_tc == other->current_tc) {
   1507         return other->active_tc.gpr[sel];
   1508     } else {
   1509         return other->tcs[other_tc].gpr[sel];
   1510     }
   1511 }
   1512 
   1513 target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
   1514 {
   1515     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1516     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1517 
   1518     if (other_tc == other->current_tc) {
   1519         return other->active_tc.LO[sel];
   1520     } else {
   1521         return other->tcs[other_tc].LO[sel];
   1522     }
   1523 }
   1524 
   1525 target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
   1526 {
   1527     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1528     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1529 
   1530     if (other_tc == other->current_tc) {
   1531         return other->active_tc.HI[sel];
   1532     } else {
   1533         return other->tcs[other_tc].HI[sel];
   1534     }
   1535 }
   1536 
   1537 target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
   1538 {
   1539     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1540     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1541 
   1542     if (other_tc == other->current_tc) {
   1543         return other->active_tc.ACX[sel];
   1544     } else {
   1545         return other->tcs[other_tc].ACX[sel];
   1546     }
   1547 }
   1548 
   1549 target_ulong helper_mftdsp(CPUMIPSState *env)
   1550 {
   1551     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1552     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1553 
   1554     if (other_tc == other->current_tc) {
   1555         return other->active_tc.DSPControl;
   1556     } else {
   1557         return other->tcs[other_tc].DSPControl;
   1558     }
   1559 }
   1560 
   1561 void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
   1562 {
   1563     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1564     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1565 
   1566     if (other_tc == other->current_tc) {
   1567         other->active_tc.gpr[sel] = arg1;
   1568     } else {
   1569         other->tcs[other_tc].gpr[sel] = arg1;
   1570     }
   1571 }
   1572 
   1573 void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
   1574 {
   1575     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1576     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1577 
   1578     if (other_tc == other->current_tc) {
   1579         other->active_tc.LO[sel] = arg1;
   1580     } else {
   1581         other->tcs[other_tc].LO[sel] = arg1;
   1582     }
   1583 }
   1584 
   1585 void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
   1586 {
   1587     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1588     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1589 
   1590     if (other_tc == other->current_tc) {
   1591         other->active_tc.HI[sel] = arg1;
   1592     } else {
   1593         other->tcs[other_tc].HI[sel] = arg1;
   1594     }
   1595 }
   1596 
   1597 void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
   1598 {
   1599     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1600     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1601 
   1602     if (other_tc == other->current_tc) {
   1603         other->active_tc.ACX[sel] = arg1;
   1604     } else {
   1605         other->tcs[other_tc].ACX[sel] = arg1;
   1606     }
   1607 }
   1608 
   1609 void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
   1610 {
   1611     int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
   1612     CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
   1613 
   1614     if (other_tc == other->current_tc) {
   1615         other->active_tc.DSPControl = arg1;
   1616     } else {
   1617         other->tcs[other_tc].DSPControl = arg1;
   1618     }
   1619 }
   1620 
   1621 /* MIPS MT functions */
   1622 target_ulong helper_dmt(void)
   1623 {
   1624     /* TODO */
   1625     return 0;
   1626 }
   1627 
   1628 target_ulong helper_emt(void)
   1629 {
   1630     /* TODO */
   1631     return 0;
   1632 }
   1633 
   1634 target_ulong helper_dvpe(CPUMIPSState *env)
   1635 {
   1636     CPUState *other_cs = first_cpu;
   1637     target_ulong prev = env->mvp->CP0_MVPControl;
   1638 
   1639     CPU_FOREACH(other_cs) {
   1640         MIPSCPU *other_cpu = MIPS_CPU(other_cs);
   1641         /* Turn off all VPEs except the one executing the dvpe.  */
   1642         if (&other_cpu->env != env) {
   1643             other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
   1644             mips_vpe_sleep(other_cpu);
   1645         }
   1646     }
   1647     return prev;
   1648 }
   1649 
   1650 target_ulong helper_evpe(CPUMIPSState *env)
   1651 {
   1652     CPUState *other_cs = first_cpu;
   1653     target_ulong prev = env->mvp->CP0_MVPControl;
   1654 
   1655     CPU_FOREACH(other_cs) {
   1656         MIPSCPU *other_cpu = MIPS_CPU(other_cs);
   1657 
   1658         if (&other_cpu->env != env
   1659             /* If the VPE is WFI, don't disturb its sleep.  */
   1660             && !mips_vpe_is_wfi(other_cpu)) {
   1661             /* Enable the VPE.  */
   1662             other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
   1663             mips_vpe_wake(other_cpu); /* And wake it up.  */
   1664         }
   1665     }
   1666     return prev;
   1667 }
   1668 
   1669 /* R6 Multi-threading */
   1670 target_ulong helper_dvp(CPUMIPSState *env)
   1671 {
   1672     CPUState *other_cs = first_cpu;
   1673     target_ulong prev = env->CP0_VPControl;
   1674 
   1675     if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
   1676         CPU_FOREACH(other_cs) {
   1677             MIPSCPU *other_cpu = MIPS_CPU(other_cs);
   1678             /* Turn off all VPs except the one executing the dvp. */
   1679             if (&other_cpu->env != env) {
   1680                 mips_vpe_sleep(other_cpu);
   1681             }
   1682         }
   1683         env->CP0_VPControl |= (1 << CP0VPCtl_DIS);
   1684     }
   1685     return prev;
   1686 }
   1687 
   1688 target_ulong helper_evp(CPUMIPSState *env)
   1689 {
   1690     CPUState *other_cs = first_cpu;
   1691     target_ulong prev = env->CP0_VPControl;
   1692 
   1693     if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
   1694         CPU_FOREACH(other_cs) {
   1695             MIPSCPU *other_cpu = MIPS_CPU(other_cs);
   1696             if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) {
   1697                 /*
   1698                  * If the VP is WFI, don't disturb its sleep.
   1699                  * Otherwise, wake it up.
   1700                  */
   1701                 mips_vpe_wake(other_cpu);
   1702             }
   1703         }
   1704         env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS);
   1705     }
   1706     return prev;
   1707 }