qemu/target/mips/tcg/sysemu/special_helper.c
<<
>>
Prefs
   1/*
   2 *  QEMU MIPS emulation: Special opcode helpers
   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 "qemu/log.h"
  23#include "cpu.h"
  24#include "exec/helper-proto.h"
  25#include "exec/exec-all.h"
  26#include "internal.h"
  27
  28/* Specials */
  29target_ulong helper_di(CPUMIPSState *env)
  30{
  31    target_ulong t0 = env->CP0_Status;
  32
  33    env->CP0_Status = t0 & ~(1 << CP0St_IE);
  34    return t0;
  35}
  36
  37target_ulong helper_ei(CPUMIPSState *env)
  38{
  39    target_ulong t0 = env->CP0_Status;
  40
  41    env->CP0_Status = t0 | (1 << CP0St_IE);
  42    return t0;
  43}
  44
  45static void debug_pre_eret(CPUMIPSState *env)
  46{
  47    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
  48        qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
  49                env->active_tc.PC, env->CP0_EPC);
  50        if (env->CP0_Status & (1 << CP0St_ERL)) {
  51            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
  52        }
  53        if (env->hflags & MIPS_HFLAG_DM) {
  54            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
  55        }
  56        qemu_log("\n");
  57    }
  58}
  59
  60static void debug_post_eret(CPUMIPSState *env)
  61{
  62    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
  63        qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
  64                env->active_tc.PC, env->CP0_EPC);
  65        if (env->CP0_Status & (1 << CP0St_ERL)) {
  66            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
  67        }
  68        if (env->hflags & MIPS_HFLAG_DM) {
  69            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
  70        }
  71        switch (cpu_mmu_index(env, false)) {
  72        case 3:
  73            qemu_log(", ERL\n");
  74            break;
  75        case MIPS_HFLAG_UM:
  76            qemu_log(", UM\n");
  77            break;
  78        case MIPS_HFLAG_SM:
  79            qemu_log(", SM\n");
  80            break;
  81        case MIPS_HFLAG_KM:
  82            qemu_log("\n");
  83            break;
  84        default:
  85            cpu_abort(env_cpu(env), "Invalid MMU mode!\n");
  86            break;
  87        }
  88    }
  89}
  90
  91bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb)
  92{
  93    MIPSCPU *cpu = MIPS_CPU(cs);
  94    CPUMIPSState *env = &cpu->env;
  95
  96    if ((env->hflags & MIPS_HFLAG_BMASK) != 0
  97        && env->active_tc.PC != tb->pc) {
  98        env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
  99        env->hflags &= ~MIPS_HFLAG_BMASK;
 100        return true;
 101    }
 102    return false;
 103}
 104
 105static inline void exception_return(CPUMIPSState *env)
 106{
 107    debug_pre_eret(env);
 108    if (env->CP0_Status & (1 << CP0St_ERL)) {
 109        mips_env_set_pc(env, env->CP0_ErrorEPC);
 110        env->CP0_Status &= ~(1 << CP0St_ERL);
 111    } else {
 112        mips_env_set_pc(env, env->CP0_EPC);
 113        env->CP0_Status &= ~(1 << CP0St_EXL);
 114    }
 115    compute_hflags(env);
 116    debug_post_eret(env);
 117}
 118
 119void helper_eret(CPUMIPSState *env)
 120{
 121    exception_return(env);
 122    env->CP0_LLAddr = 1;
 123    env->lladdr = 1;
 124}
 125
 126void helper_eretnc(CPUMIPSState *env)
 127{
 128    exception_return(env);
 129}
 130
 131void helper_deret(CPUMIPSState *env)
 132{
 133    debug_pre_eret(env);
 134
 135    env->hflags &= ~MIPS_HFLAG_DM;
 136    compute_hflags(env);
 137
 138    mips_env_set_pc(env, env->CP0_DEPC);
 139
 140    debug_post_eret(env);
 141}
 142
 143void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
 144{
 145    static const char *const type_name[] = {
 146        "Primary Instruction",
 147        "Primary Data or Unified Primary",
 148        "Tertiary",
 149        "Secondary"
 150    };
 151    uint32_t cache_type = extract32(op, 0, 2);
 152    uint32_t cache_operation = extract32(op, 2, 3);
 153    target_ulong index = addr & 0x1fffffff;
 154
 155    switch (cache_operation) {
 156    case 0b010: /* Index Store Tag */
 157        memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
 158                                     MO_64, MEMTXATTRS_UNSPECIFIED);
 159        break;
 160    case 0b001: /* Index Load Tag */
 161        memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
 162                                    MO_64, MEMTXATTRS_UNSPECIFIED);
 163        break;
 164    case 0b000: /* Index Invalidate */
 165    case 0b100: /* Hit Invalidate */
 166    case 0b110: /* Hit Writeback */
 167        /* no-op */
 168        break;
 169    default:
 170        qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n",
 171                      cache_operation, type_name[cache_type]);
 172        break;
 173    }
 174}
 175