qemu/target/alpha/cpu.c
<<
>>
Prefs
   1/*
   2 * QEMU Alpha CPU
   3 *
   4 * Copyright (c) 2007 Jocelyn Mayer
   5 * Copyright (c) 2012 SUSE LINUX Products GmbH
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2.1 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this library; if not, see
  19 * <http://www.gnu.org/licenses/lgpl-2.1.html>
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "qapi/error.h"
  24#include "cpu.h"
  25#include "qemu-common.h"
  26#include "exec/exec-all.h"
  27
  28
  29static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
  30{
  31    AlphaCPU *cpu = ALPHA_CPU(cs);
  32
  33    cpu->env.pc = value;
  34}
  35
  36static bool alpha_cpu_has_work(CPUState *cs)
  37{
  38    /* Here we are checking to see if the CPU should wake up from HALT.
  39       We will have gotten into this state only for WTINT from PALmode.  */
  40    /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU
  41       asleep even if (some) interrupts have been asserted.  For now,
  42       assume that if a CPU really wants to stay asleep, it will mask
  43       interrupts at the chipset level, which will prevent these bits
  44       from being set in the first place.  */
  45    return cs->interrupt_request & (CPU_INTERRUPT_HARD
  46                                    | CPU_INTERRUPT_TIMER
  47                                    | CPU_INTERRUPT_SMP
  48                                    | CPU_INTERRUPT_MCHK);
  49}
  50
  51static void alpha_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
  52{
  53    info->mach = bfd_mach_alpha_ev6;
  54    info->print_insn = print_insn_alpha;
  55}
  56
  57static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)
  58{
  59    CPUState *cs = CPU(dev);
  60    AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev);
  61    Error *local_err = NULL;
  62
  63    cpu_exec_realizefn(cs, &local_err);
  64    if (local_err != NULL) {
  65        error_propagate(errp, local_err);
  66        return;
  67    }
  68
  69    qemu_init_vcpu(cs);
  70
  71    acc->parent_realize(dev, errp);
  72}
  73
  74static void alpha_cpu_list_entry(gpointer data, gpointer user_data)
  75{
  76    ObjectClass *oc = data;
  77    CPUListState *s = user_data;
  78
  79    (*s->cpu_fprintf)(s->file, "  %s\n",
  80                      object_class_get_name(oc));
  81}
  82
  83void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf)
  84{
  85    CPUListState s = {
  86        .file = f,
  87        .cpu_fprintf = cpu_fprintf,
  88    };
  89    GSList *list;
  90
  91    list = object_class_get_list_sorted(TYPE_ALPHA_CPU, false);
  92    (*cpu_fprintf)(f, "Available CPUs:\n");
  93    g_slist_foreach(list, alpha_cpu_list_entry, &s);
  94    g_slist_free(list);
  95}
  96
  97/* Models */
  98typedef struct AlphaCPUAlias {
  99    const char *alias;
 100    const char *typename;
 101} AlphaCPUAlias;
 102
 103static const AlphaCPUAlias alpha_cpu_aliases[] = {
 104    { "21064",   ALPHA_CPU_TYPE_NAME("ev4") },
 105    { "21164",   ALPHA_CPU_TYPE_NAME("ev5") },
 106    { "21164a",  ALPHA_CPU_TYPE_NAME("ev56") },
 107    { "21164pc", ALPHA_CPU_TYPE_NAME("pca56") },
 108    { "21264",   ALPHA_CPU_TYPE_NAME("ev6") },
 109    { "21264a",  ALPHA_CPU_TYPE_NAME("ev67") },
 110};
 111
 112static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model)
 113{
 114    ObjectClass *oc;
 115    char *typename;
 116    int i;
 117
 118    oc = object_class_by_name(cpu_model);
 119    if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL &&
 120        !object_class_is_abstract(oc)) {
 121        return oc;
 122    }
 123
 124    for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) {
 125        if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) {
 126            oc = object_class_by_name(alpha_cpu_aliases[i].typename);
 127            assert(oc != NULL && !object_class_is_abstract(oc));
 128            return oc;
 129        }
 130    }
 131
 132    typename = g_strdup_printf(ALPHA_CPU_TYPE_NAME("%s"), cpu_model);
 133    oc = object_class_by_name(typename);
 134    g_free(typename);
 135    if (oc != NULL && object_class_is_abstract(oc)) {
 136        oc = NULL;
 137    }
 138
 139    /* TODO: remove match everything nonsense */
 140    /* Default to ev67; no reason not to emulate insns by default. */
 141    if (!oc) {
 142        oc = object_class_by_name(ALPHA_CPU_TYPE_NAME("ev67"));
 143    }
 144
 145    return oc;
 146}
 147
 148static void ev4_cpu_initfn(Object *obj)
 149{
 150    AlphaCPU *cpu = ALPHA_CPU(obj);
 151    CPUAlphaState *env = &cpu->env;
 152
 153    env->implver = IMPLVER_2106x;
 154}
 155
 156static void ev5_cpu_initfn(Object *obj)
 157{
 158    AlphaCPU *cpu = ALPHA_CPU(obj);
 159    CPUAlphaState *env = &cpu->env;
 160
 161    env->implver = IMPLVER_21164;
 162}
 163
 164static void ev56_cpu_initfn(Object *obj)
 165{
 166    AlphaCPU *cpu = ALPHA_CPU(obj);
 167    CPUAlphaState *env = &cpu->env;
 168
 169    env->amask |= AMASK_BWX;
 170}
 171
 172static void pca56_cpu_initfn(Object *obj)
 173{
 174    AlphaCPU *cpu = ALPHA_CPU(obj);
 175    CPUAlphaState *env = &cpu->env;
 176
 177    env->amask |= AMASK_MVI;
 178}
 179
 180static void ev6_cpu_initfn(Object *obj)
 181{
 182    AlphaCPU *cpu = ALPHA_CPU(obj);
 183    CPUAlphaState *env = &cpu->env;
 184
 185    env->implver = IMPLVER_21264;
 186    env->amask = AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP;
 187}
 188
 189static void ev67_cpu_initfn(Object *obj)
 190{
 191    AlphaCPU *cpu = ALPHA_CPU(obj);
 192    CPUAlphaState *env = &cpu->env;
 193
 194    env->amask |= AMASK_CIX | AMASK_PREFETCH;
 195}
 196
 197static void alpha_cpu_initfn(Object *obj)
 198{
 199    CPUState *cs = CPU(obj);
 200    AlphaCPU *cpu = ALPHA_CPU(obj);
 201    CPUAlphaState *env = &cpu->env;
 202
 203    cs->env_ptr = env;
 204    tlb_flush(cs);
 205
 206    env->lock_addr = -1;
 207#if defined(CONFIG_USER_ONLY)
 208    env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
 209    cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
 210                               | FPCR_UNFD | FPCR_INED | FPCR_DNOD
 211                               | FPCR_DYN_NORMAL));
 212#else
 213    env->flags = ENV_FLAG_PAL_MODE | ENV_FLAG_FEN;
 214#endif
 215}
 216
 217static void alpha_cpu_class_init(ObjectClass *oc, void *data)
 218{
 219    DeviceClass *dc = DEVICE_CLASS(oc);
 220    CPUClass *cc = CPU_CLASS(oc);
 221    AlphaCPUClass *acc = ALPHA_CPU_CLASS(oc);
 222
 223    device_class_set_parent_realize(dc, alpha_cpu_realizefn,
 224                                    &acc->parent_realize);
 225
 226    cc->class_by_name = alpha_cpu_class_by_name;
 227    cc->has_work = alpha_cpu_has_work;
 228    cc->do_interrupt = alpha_cpu_do_interrupt;
 229    cc->cpu_exec_interrupt = alpha_cpu_exec_interrupt;
 230    cc->dump_state = alpha_cpu_dump_state;
 231    cc->set_pc = alpha_cpu_set_pc;
 232    cc->gdb_read_register = alpha_cpu_gdb_read_register;
 233    cc->gdb_write_register = alpha_cpu_gdb_write_register;
 234#ifdef CONFIG_USER_ONLY
 235    cc->handle_mmu_fault = alpha_cpu_handle_mmu_fault;
 236#else
 237    cc->do_transaction_failed = alpha_cpu_do_transaction_failed;
 238    cc->do_unaligned_access = alpha_cpu_do_unaligned_access;
 239    cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
 240    dc->vmsd = &vmstate_alpha_cpu;
 241#endif
 242    cc->disas_set_info = alpha_cpu_disas_set_info;
 243    cc->tcg_initialize = alpha_translate_init;
 244
 245    cc->gdb_num_core_regs = 67;
 246}
 247
 248#define DEFINE_ALPHA_CPU_TYPE(base_type, cpu_model, initfn) \
 249     {                                                      \
 250         .parent = base_type,                               \
 251         .instance_init = initfn,                           \
 252         .name = ALPHA_CPU_TYPE_NAME(cpu_model),            \
 253     }
 254
 255static const TypeInfo alpha_cpu_type_infos[] = {
 256    {
 257        .name = TYPE_ALPHA_CPU,
 258        .parent = TYPE_CPU,
 259        .instance_size = sizeof(AlphaCPU),
 260        .instance_init = alpha_cpu_initfn,
 261        .abstract = true,
 262        .class_size = sizeof(AlphaCPUClass),
 263        .class_init = alpha_cpu_class_init,
 264    },
 265    DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev4", ev4_cpu_initfn),
 266    DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev5", ev5_cpu_initfn),
 267    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev5"), "ev56", ev56_cpu_initfn),
 268    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev56"), "pca56",
 269                          pca56_cpu_initfn),
 270    DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev6", ev6_cpu_initfn),
 271    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev6"), "ev67", ev67_cpu_initfn),
 272    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev67"), "ev68", NULL),
 273};
 274
 275DEFINE_TYPES(alpha_cpu_type_infos)
 276