qemu/target-lm32/helper.c
<<
>>
Prefs
   1/*
   2 *  LatticeMico32 helper routines.
   3 *
   4 *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
   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
  20#include "cpu.h"
  21#include "host-utils.h"
  22
  23int cpu_lm32_handle_mmu_fault(CPULM32State *env, target_ulong address, int rw,
  24                              int mmu_idx)
  25{
  26    int prot;
  27
  28    address &= TARGET_PAGE_MASK;
  29    prot = PAGE_BITS;
  30    if (env->flags & LM32_FLAG_IGNORE_MSB) {
  31        tlb_set_page(env, address, address & 0x7fffffff, prot, mmu_idx,
  32                TARGET_PAGE_SIZE);
  33    } else {
  34        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
  35    }
  36
  37    return 0;
  38}
  39
  40target_phys_addr_t cpu_get_phys_page_debug(CPULM32State *env, target_ulong addr)
  41{
  42    return addr & TARGET_PAGE_MASK;
  43}
  44
  45void do_interrupt(CPULM32State *env)
  46{
  47    qemu_log_mask(CPU_LOG_INT,
  48            "exception at pc=%x type=%x\n", env->pc, env->exception_index);
  49
  50    switch (env->exception_index) {
  51    case EXCP_INSN_BUS_ERROR:
  52    case EXCP_DATA_BUS_ERROR:
  53    case EXCP_DIVIDE_BY_ZERO:
  54    case EXCP_IRQ:
  55    case EXCP_SYSTEMCALL:
  56        /* non-debug exceptions */
  57        env->regs[R_EA] = env->pc;
  58        env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
  59        env->ie &= ~IE_IE;
  60        if (env->dc & DC_RE) {
  61            env->pc = env->deba + (env->exception_index * 32);
  62        } else {
  63            env->pc = env->eba + (env->exception_index * 32);
  64        }
  65        log_cpu_state_mask(CPU_LOG_INT, env, 0);
  66        break;
  67    case EXCP_BREAKPOINT:
  68    case EXCP_WATCHPOINT:
  69        /* debug exceptions */
  70        env->regs[R_BA] = env->pc;
  71        env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
  72        env->ie &= ~IE_IE;
  73        env->pc = env->deba + (env->exception_index * 32);
  74        log_cpu_state_mask(CPU_LOG_INT, env, 0);
  75        break;
  76    default:
  77        cpu_abort(env, "unhandled exception type=%d\n",
  78                  env->exception_index);
  79        break;
  80    }
  81}
  82
  83typedef struct {
  84    const char *name;
  85    uint32_t revision;
  86    uint8_t num_interrupts;
  87    uint8_t num_breakpoints;
  88    uint8_t num_watchpoints;
  89    uint32_t features;
  90} LM32Def;
  91
  92static const LM32Def lm32_defs[] = {
  93    {
  94        .name = "lm32-basic",
  95        .revision = 3,
  96        .num_interrupts = 32,
  97        .num_breakpoints = 4,
  98        .num_watchpoints = 4,
  99        .features = (LM32_FEATURE_SHIFT
 100                     | LM32_FEATURE_SIGN_EXTEND
 101                     | LM32_FEATURE_CYCLE_COUNT),
 102    },
 103    {
 104        .name = "lm32-standard",
 105        .revision = 3,
 106        .num_interrupts = 32,
 107        .num_breakpoints = 4,
 108        .num_watchpoints = 4,
 109        .features = (LM32_FEATURE_MULTIPLY
 110                     | LM32_FEATURE_DIVIDE
 111                     | LM32_FEATURE_SHIFT
 112                     | LM32_FEATURE_SIGN_EXTEND
 113                     | LM32_FEATURE_I_CACHE
 114                     | LM32_FEATURE_CYCLE_COUNT),
 115    },
 116    {
 117        .name = "lm32-full",
 118        .revision = 3,
 119        .num_interrupts = 32,
 120        .num_breakpoints = 4,
 121        .num_watchpoints = 4,
 122        .features = (LM32_FEATURE_MULTIPLY
 123                     | LM32_FEATURE_DIVIDE
 124                     | LM32_FEATURE_SHIFT
 125                     | LM32_FEATURE_SIGN_EXTEND
 126                     | LM32_FEATURE_I_CACHE
 127                     | LM32_FEATURE_D_CACHE
 128                     | LM32_FEATURE_CYCLE_COUNT),
 129    }
 130};
 131
 132void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf)
 133{
 134    int i;
 135
 136    cpu_fprintf(f, "Available CPUs:\n");
 137    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
 138        cpu_fprintf(f, "  %s\n", lm32_defs[i].name);
 139    }
 140}
 141
 142static const LM32Def *cpu_lm32_find_by_name(const char *name)
 143{
 144    int i;
 145
 146    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
 147        if (strcasecmp(name, lm32_defs[i].name) == 0) {
 148            return &lm32_defs[i];
 149        }
 150    }
 151
 152    return NULL;
 153}
 154
 155static uint32_t cfg_by_def(const LM32Def *def)
 156{
 157    uint32_t cfg = 0;
 158
 159    if (def->features & LM32_FEATURE_MULTIPLY) {
 160        cfg |= CFG_M;
 161    }
 162
 163    if (def->features & LM32_FEATURE_DIVIDE) {
 164        cfg |= CFG_D;
 165    }
 166
 167    if (def->features & LM32_FEATURE_SHIFT) {
 168        cfg |= CFG_S;
 169    }
 170
 171    if (def->features & LM32_FEATURE_SIGN_EXTEND) {
 172        cfg |= CFG_X;
 173    }
 174
 175    if (def->features & LM32_FEATURE_I_CACHE) {
 176        cfg |= CFG_IC;
 177    }
 178
 179    if (def->features & LM32_FEATURE_D_CACHE) {
 180        cfg |= CFG_DC;
 181    }
 182
 183    if (def->features & LM32_FEATURE_CYCLE_COUNT) {
 184        cfg |= CFG_CC;
 185    }
 186
 187    cfg |= (def->num_interrupts << CFG_INT_SHIFT);
 188    cfg |= (def->num_breakpoints << CFG_BP_SHIFT);
 189    cfg |= (def->num_watchpoints << CFG_WP_SHIFT);
 190    cfg |= (def->revision << CFG_REV_SHIFT);
 191
 192    return cfg;
 193}
 194
 195CPULM32State *cpu_lm32_init(const char *cpu_model)
 196{
 197    LM32CPU *cpu;
 198    CPULM32State *env;
 199    const LM32Def *def;
 200    static int tcg_initialized;
 201
 202    def = cpu_lm32_find_by_name(cpu_model);
 203    if (!def) {
 204        return NULL;
 205    }
 206
 207    cpu = LM32_CPU(object_new(TYPE_LM32_CPU));
 208    env = &cpu->env;
 209
 210    env->features = def->features;
 211    env->num_bps = def->num_breakpoints;
 212    env->num_wps = def->num_watchpoints;
 213    env->cfg = cfg_by_def(def);
 214
 215    qemu_init_vcpu(env);
 216
 217    if (tcg_enabled() && !tcg_initialized) {
 218        tcg_initialized = 1;
 219        lm32_translate_init();
 220    }
 221
 222    return env;
 223}
 224
 225/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory
 226 * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
 227 * 0x80000000-0xffffffff is not cached and used to access IO devices. */
 228void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value)
 229{
 230    if (value) {
 231        env->flags |= LM32_FLAG_IGNORE_MSB;
 232    } else {
 233        env->flags &= ~LM32_FLAG_IGNORE_MSB;
 234    }
 235}
 236
 237void cpu_state_reset(CPULM32State *env)
 238{
 239    cpu_reset(ENV_GET_CPU(env));
 240}
 241
 242