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