qemu

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

cp0.c (3801B)


      1 /*
      2  * QEMU MIPS CPU
      3  *
      4  * Copyright (c) 2012 SUSE LINUX Products GmbH
      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.1 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
     18  * <http://www.gnu.org/licenses/lgpl-2.1.html>
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "cpu.h"
     23 #include "internal.h"
     24 #include "exec/exec-all.h"
     25 
     26 /* Called for updates to CP0_Status.  */
     27 void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
     28 {
     29     int32_t tcstatus, *tcst;
     30     uint32_t v = cpu->CP0_Status;
     31     uint32_t cu, mx, asid, ksu;
     32     uint32_t mask = ((1 << CP0TCSt_TCU3)
     33                        | (1 << CP0TCSt_TCU2)
     34                        | (1 << CP0TCSt_TCU1)
     35                        | (1 << CP0TCSt_TCU0)
     36                        | (1 << CP0TCSt_TMX)
     37                        | (3 << CP0TCSt_TKSU)
     38                        | (0xff << CP0TCSt_TASID));
     39 
     40     cu = (v >> CP0St_CU0) & 0xf;
     41     mx = (v >> CP0St_MX) & 0x1;
     42     ksu = (v >> CP0St_KSU) & 0x3;
     43     asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
     44 
     45     tcstatus = cu << CP0TCSt_TCU0;
     46     tcstatus |= mx << CP0TCSt_TMX;
     47     tcstatus |= ksu << CP0TCSt_TKSU;
     48     tcstatus |= asid;
     49 
     50     if (tc == cpu->current_tc) {
     51         tcst = &cpu->active_tc.CP0_TCStatus;
     52     } else {
     53         tcst = &cpu->tcs[tc].CP0_TCStatus;
     54     }
     55 
     56     *tcst &= ~mask;
     57     *tcst |= tcstatus;
     58     compute_hflags(cpu);
     59 }
     60 
     61 void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
     62 {
     63     uint32_t mask = env->CP0_Status_rw_bitmask;
     64     target_ulong old = env->CP0_Status;
     65 
     66     if (env->insn_flags & ISA_MIPS_R6) {
     67         bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3;
     68 #if defined(TARGET_MIPS64)
     69         uint32_t ksux = (1 << CP0St_KX) & val;
     70         ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */
     71         ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */
     72         val = (val & ~(7 << CP0St_UX)) | ksux;
     73 #endif
     74         if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) {
     75             mask &= ~(3 << CP0St_KSU);
     76         }
     77         mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val);
     78     }
     79 
     80     env->CP0_Status = (old & ~mask) | (val & mask);
     81 #if defined(TARGET_MIPS64)
     82     if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) {
     83         /* Access to at least one of the 64-bit segments has been disabled */
     84         tlb_flush(env_cpu(env));
     85     }
     86 #endif
     87     if (ase_mt_available(env)) {
     88         sync_c0_status(env, env, env->current_tc);
     89     } else {
     90         compute_hflags(env);
     91     }
     92 }
     93 
     94 void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val)
     95 {
     96     uint32_t mask = 0x00C00300;
     97     uint32_t old = env->CP0_Cause;
     98     int i;
     99 
    100     if (env->insn_flags & ISA_MIPS_R2) {
    101         mask |= 1 << CP0Ca_DC;
    102     }
    103     if (env->insn_flags & ISA_MIPS_R6) {
    104         mask &= ~((1 << CP0Ca_WP) & val);
    105     }
    106 
    107     env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask);
    108 
    109     if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
    110         if (env->CP0_Cause & (1 << CP0Ca_DC)) {
    111             cpu_mips_stop_count(env);
    112         } else {
    113             cpu_mips_start_count(env);
    114         }
    115     }
    116 
    117     /* Set/reset software interrupts */
    118     for (i = 0 ; i < 2 ; i++) {
    119         if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
    120             cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
    121         }
    122     }
    123 }