qemu

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

op_helper.c (7884B)


      1 /*
      2  *  MIPS emulation helpers for qemu.
      3  *
      4  *  Copyright (c) 2004-2005 Jocelyn Mayer
      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 <http://www.gnu.org/licenses/>.
     18  *
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "cpu.h"
     23 #include "internal.h"
     24 #include "exec/helper-proto.h"
     25 #include "exec/exec-all.h"
     26 #include "exec/memop.h"
     27 #include "fpu_helper.h"
     28 
     29 static inline target_ulong bitswap(target_ulong v)
     30 {
     31     v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
     32               ((v & (target_ulong)0x5555555555555555ULL) << 1);
     33     v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
     34               ((v & (target_ulong)0x3333333333333333ULL) << 2);
     35     v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
     36               ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
     37     return v;
     38 }
     39 
     40 #ifdef TARGET_MIPS64
     41 target_ulong helper_dbitswap(target_ulong rt)
     42 {
     43     return bitswap(rt);
     44 }
     45 #endif
     46 
     47 target_ulong helper_bitswap(target_ulong rt)
     48 {
     49     return (int32_t)bitswap(rt);
     50 }
     51 
     52 target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,
     53                         uint32_t stripe)
     54 {
     55     int i;
     56     uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff);
     57     uint64_t tmp1 = tmp0;
     58     for (i = 0; i <= 46; i++) {
     59         int s;
     60         if (i & 0x8) {
     61             s = shift;
     62         } else {
     63             s = shiftx;
     64         }
     65 
     66         if (stripe != 0 && !(i & 0x4)) {
     67             s = ~s;
     68         }
     69         if (s & 0x10) {
     70             if (tmp0 & (1LL << (i + 16))) {
     71                 tmp1 |= 1LL << i;
     72             } else {
     73                 tmp1 &= ~(1LL << i);
     74             }
     75         }
     76     }
     77 
     78     uint64_t tmp2 = tmp1;
     79     for (i = 0; i <= 38; i++) {
     80         int s;
     81         if (i & 0x4) {
     82             s = shift;
     83         } else {
     84             s = shiftx;
     85         }
     86 
     87         if (s & 0x8) {
     88             if (tmp1 & (1LL << (i + 8))) {
     89                 tmp2 |= 1LL << i;
     90             } else {
     91                 tmp2 &= ~(1LL << i);
     92             }
     93         }
     94     }
     95 
     96     uint64_t tmp3 = tmp2;
     97     for (i = 0; i <= 34; i++) {
     98         int s;
     99         if (i & 0x2) {
    100             s = shift;
    101         } else {
    102             s = shiftx;
    103         }
    104         if (s & 0x4) {
    105             if (tmp2 & (1LL << (i + 4))) {
    106                 tmp3 |= 1LL << i;
    107             } else {
    108                 tmp3 &= ~(1LL << i);
    109             }
    110         }
    111     }
    112 
    113     uint64_t tmp4 = tmp3;
    114     for (i = 0; i <= 32; i++) {
    115         int s;
    116         if (i & 0x1) {
    117             s = shift;
    118         } else {
    119             s = shiftx;
    120         }
    121         if (s & 0x2) {
    122             if (tmp3 & (1LL << (i + 2))) {
    123                 tmp4 |= 1LL << i;
    124             } else {
    125                 tmp4 &= ~(1LL << i);
    126             }
    127         }
    128     }
    129 
    130     uint64_t tmp5 = tmp4;
    131     for (i = 0; i <= 31; i++) {
    132         int s;
    133         s = shift;
    134         if (s & 0x1) {
    135             if (tmp4 & (1LL << (i + 1))) {
    136                 tmp5 |= 1LL << i;
    137             } else {
    138                 tmp5 &= ~(1LL << i);
    139             }
    140         }
    141     }
    142 
    143     return (int64_t)(int32_t)(uint32_t)tmp5;
    144 }
    145 
    146 void helper_fork(target_ulong arg1, target_ulong arg2)
    147 {
    148     /*
    149      * arg1 = rt, arg2 = rs
    150      * TODO: store to TC register
    151      */
    152 }
    153 
    154 target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
    155 {
    156     target_long arg1 = arg;
    157 
    158     if (arg1 < 0) {
    159         /* No scheduling policy implemented. */
    160         if (arg1 != -2) {
    161             if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
    162                 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
    163                 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
    164                 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
    165                 do_raise_exception(env, EXCP_THREAD, GETPC());
    166             }
    167         }
    168     } else if (arg1 == 0) {
    169         if (0) {
    170             /* TODO: TC underflow */
    171             env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
    172             do_raise_exception(env, EXCP_THREAD, GETPC());
    173         } else {
    174             /* TODO: Deallocate TC */
    175         }
    176     } else if (arg1 > 0) {
    177         /* Yield qualifier inputs not implemented. */
    178         env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
    179         env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
    180         do_raise_exception(env, EXCP_THREAD, GETPC());
    181     }
    182     return env->CP0_YQMask;
    183 }
    184 
    185 static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
    186 {
    187     if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
    188         return;
    189     }
    190     do_raise_exception(env, EXCP_RI, pc);
    191 }
    192 
    193 target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
    194 {
    195     check_hwrena(env, 0, GETPC());
    196     return env->CP0_EBase & 0x3ff;
    197 }
    198 
    199 target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
    200 {
    201     check_hwrena(env, 1, GETPC());
    202     return env->SYNCI_Step;
    203 }
    204 
    205 target_ulong helper_rdhwr_cc(CPUMIPSState *env)
    206 {
    207     check_hwrena(env, 2, GETPC());
    208 #ifdef CONFIG_USER_ONLY
    209     return env->CP0_Count;
    210 #else
    211     return (int32_t)cpu_mips_get_count(env);
    212 #endif
    213 }
    214 
    215 target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
    216 {
    217     check_hwrena(env, 3, GETPC());
    218     return env->CCRes;
    219 }
    220 
    221 target_ulong helper_rdhwr_performance(CPUMIPSState *env)
    222 {
    223     check_hwrena(env, 4, GETPC());
    224     return env->CP0_Performance0;
    225 }
    226 
    227 target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
    228 {
    229     check_hwrena(env, 5, GETPC());
    230     return (env->CP0_Config5 >> CP0C5_XNP) & 1;
    231 }
    232 
    233 void helper_pmon(CPUMIPSState *env, int function)
    234 {
    235     function /= 2;
    236     switch (function) {
    237     case 2: /* TODO: char inbyte(int waitflag); */
    238         if (env->active_tc.gpr[4] == 0) {
    239             env->active_tc.gpr[2] = -1;
    240         }
    241         /* Fall through */
    242     case 11: /* TODO: char inbyte (void); */
    243         env->active_tc.gpr[2] = -1;
    244         break;
    245     case 3:
    246     case 12:
    247         printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
    248         break;
    249     case 17:
    250         break;
    251     case 158:
    252         {
    253             unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
    254             printf("%s", fmt);
    255         }
    256         break;
    257     }
    258 }
    259 
    260 #if !defined(CONFIG_USER_ONLY)
    261 
    262 void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
    263                                   MMUAccessType access_type,
    264                                   int mmu_idx, uintptr_t retaddr)
    265 {
    266     MIPSCPU *cpu = MIPS_CPU(cs);
    267     CPUMIPSState *env = &cpu->env;
    268     int error_code = 0;
    269     int excp;
    270 
    271     if (!(env->hflags & MIPS_HFLAG_DM)) {
    272         env->CP0_BadVAddr = addr;
    273     }
    274 
    275     if (access_type == MMU_DATA_STORE) {
    276         excp = EXCP_AdES;
    277     } else {
    278         excp = EXCP_AdEL;
    279         if (access_type == MMU_INST_FETCH) {
    280             error_code |= EXCP_INST_NOTAVAIL;
    281         }
    282     }
    283 
    284     do_raise_exception_err(env, excp, error_code, retaddr);
    285 }
    286 
    287 void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
    288                                     vaddr addr, unsigned size,
    289                                     MMUAccessType access_type,
    290                                     int mmu_idx, MemTxAttrs attrs,
    291                                     MemTxResult response, uintptr_t retaddr)
    292 {
    293     MIPSCPU *cpu = MIPS_CPU(cs);
    294     MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu);
    295     CPUMIPSState *env = &cpu->env;
    296 
    297     if (access_type == MMU_INST_FETCH) {
    298         do_raise_exception(env, EXCP_IBE, retaddr);
    299     } else if (!mcc->no_data_aborts) {
    300         do_raise_exception(env, EXCP_DBE, retaddr);
    301     }
    302 }
    303 #endif /* !CONFIG_USER_ONLY */