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 "qemu/qemu-print.h"
  25#include "cpu.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
  78    qemu_printf("  %s\n", object_class_get_name(oc));
  79}
  80
  81void alpha_cpu_list(void)
  82{
  83    GSList *list;
  84
  85    list = object_class_get_list_sorted(TYPE_ALPHA_CPU, false);
  86    qemu_printf("Available CPUs:\n");
  87    g_slist_foreach(list, alpha_cpu_list_entry, NULL);
  88    g_slist_free(list);
  89}
  90
  91/* Models */
  92typedef struct AlphaCPUAlias {
  93    const char *alias;
  94    const char *typename;
  95} AlphaCPUAlias;
  96
  97static const AlphaCPUAlias alpha_cpu_aliases[] = {
  98    { "21064",   ALPHA_CPU_TYPE_NAME("ev4") },
  99    { "21164",   ALPHA_CPU_TYPE_NAME("ev5") },
 100    { "21164a",  ALPHA_CPU_TYPE_NAME("ev56") },
 101    { "21164pc", ALPHA_CPU_TYPE_NAME("pca56") },
 102    { "21264",   ALPHA_CPU_TYPE_NAME("ev6") },
 103    { "21264a",  ALPHA_CPU_TYPE_NAME("ev67") },
 104};
 105
 106static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model)
 107{
 108    ObjectClass *oc;
 109    char *typename;
 110    int i;
 111
 112    oc = object_class_by_name(cpu_model);
 113    if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL &&
 114        !object_class_is_abstract(oc)) {
 115        return oc;
 116    }
 117
 118    for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) {
 119        if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) {
 120            oc = object_class_by_name(alpha_cpu_aliases[i].typename);
 121            assert(oc != NULL && !object_class_is_abstract(oc));
 122            return oc;
 123        }
 124    }
 125
 126    typename = g_strdup_printf(ALPHA_CPU_TYPE_NAME("%s"), cpu_model);
 127    oc = object_class_by_name(typename);
 128    g_free(typename);
 129    if (oc != NULL && object_class_is_abstract(oc)) {
 130        oc = NULL;
 131    }
 132
 133    /* TODO: remove match everything nonsense */
 134    /* Default to ev67; no reason not to emulate insns by default. */
 135    if (!oc) {
 136        oc = object_class_by_name(ALPHA_CPU_TYPE_NAME("ev67"));
 137    }
 138
 139    return oc;
 140}
 141
 142static void ev4_cpu_initfn(Object *obj)
 143{
 144    AlphaCPU *cpu = ALPHA_CPU(obj);
 145    CPUAlphaState *env = &cpu->env;
 146
 147    env->implver = IMPLVER_2106x;
 148}
 149
 150static void ev5_cpu_initfn(Object *obj)
 151{
 152    AlphaCPU *cpu = ALPHA_CPU(obj);
 153    CPUAlphaState *env = &cpu->env;
 154
 155    env->implver = IMPLVER_21164;
 156}
 157
 158static void ev56_cpu_initfn(Object *obj)
 159{
 160    AlphaCPU *cpu = ALPHA_CPU(obj);
 161    CPUAlphaState *env = &cpu->env;
 162
 163    env->amask |= AMASK_BWX;
 164}
 165
 166static void pca56_cpu_initfn(Object *obj)
 167{
 168    AlphaCPU *cpu = ALPHA_CPU(obj);
 169    CPUAlphaState *env = &cpu->env;
 170
 171    env->amask |= AMASK_MVI;
 172}
 173
 174static void ev6_cpu_initfn(Object *obj)
 175{
 176    AlphaCPU *cpu = ALPHA_CPU(obj);
 177    CPUAlphaState *env = &cpu->env;
 178
 179    env->implver = IMPLVER_21264;
 180    env->amask = AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP;
 181}
 182
 183static void ev67_cpu_initfn(Object *obj)
 184{
 185    AlphaCPU *cpu = ALPHA_CPU(obj);
 186    CPUAlphaState *env = &cpu->env;
 187
 188    env->amask |= AMASK_CIX | AMASK_PREFETCH;
 189}
 190
 191static void alpha_cpu_initfn(Object *obj)
 192{
 193    AlphaCPU *cpu = ALPHA_CPU(obj);
 194    CPUAlphaState *env = &cpu->env;
 195
 196    cpu_set_cpustate_pointers(cpu);
 197
 198    env->lock_addr = -1;
 199#if defined(CONFIG_USER_ONLY)
 200    env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
 201    cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
 202                                         | FPCR_UNFD | FPCR_INED | FPCR_DNOD
 203                                         | FPCR_DYN_NORMAL) << 32);
 204#else
 205    env->flags = ENV_FLAG_PAL_MODE | ENV_FLAG_FEN;
 206#endif
 207}
 208
 209#ifndef CONFIG_USER_ONLY
 210#include "hw/core/sysemu-cpu-ops.h"
 211
 212static const struct SysemuCPUOps alpha_sysemu_ops = {
 213    .get_phys_page_debug = alpha_cpu_get_phys_page_debug,
 214};
 215#endif
 216
 217#include "hw/core/tcg-cpu-ops.h"
 218
 219static const struct TCGCPUOps alpha_tcg_ops = {
 220    .initialize = alpha_translate_init,
 221
 222#ifdef CONFIG_USER_ONLY
 223    .record_sigsegv = alpha_cpu_record_sigsegv,
 224    .record_sigbus = alpha_cpu_record_sigbus,
 225#else
 226    .tlb_fill = alpha_cpu_tlb_fill,
 227    .cpu_exec_interrupt = alpha_cpu_exec_interrupt,
 228    .do_interrupt = alpha_cpu_do_interrupt,
 229    .do_transaction_failed = alpha_cpu_do_transaction_failed,
 230    .do_unaligned_access = alpha_cpu_do_unaligned_access,
 231#endif /* !CONFIG_USER_ONLY */
 232};
 233
 234static void alpha_cpu_class_init(ObjectClass *oc, void *data)
 235{
 236    DeviceClass *dc = DEVICE_CLASS(oc);
 237    CPUClass *cc = CPU_CLASS(oc);
 238    AlphaCPUClass *acc = ALPHA_CPU_CLASS(oc);
 239
 240    device_class_set_parent_realize(dc, alpha_cpu_realizefn,
 241                                    &acc->parent_realize);
 242
 243    cc->class_by_name = alpha_cpu_class_by_name;
 244    cc->has_work = alpha_cpu_has_work;
 245    cc->dump_state = alpha_cpu_dump_state;
 246    cc->set_pc = alpha_cpu_set_pc;
 247    cc->gdb_read_register = alpha_cpu_gdb_read_register;
 248    cc->gdb_write_register = alpha_cpu_gdb_write_register;
 249#ifndef CONFIG_USER_ONLY
 250    dc->vmsd = &vmstate_alpha_cpu;
 251    cc->sysemu_ops = &alpha_sysemu_ops;
 252#endif
 253    cc->disas_set_info = alpha_cpu_disas_set_info;
 254
 255    cc->tcg_ops = &alpha_tcg_ops;
 256    cc->gdb_num_core_regs = 67;
 257}
 258
 259#define DEFINE_ALPHA_CPU_TYPE(base_type, cpu_model, initfn) \
 260     {                                                      \
 261         .parent = base_type,                               \
 262         .instance_init = initfn,                           \
 263         .name = ALPHA_CPU_TYPE_NAME(cpu_model),            \
 264     }
 265
 266static const TypeInfo alpha_cpu_type_infos[] = {
 267    {
 268        .name = TYPE_ALPHA_CPU,
 269        .parent = TYPE_CPU,
 270        .instance_size = sizeof(AlphaCPU),
 271        .instance_init = alpha_cpu_initfn,
 272        .abstract = true,
 273        .class_size = sizeof(AlphaCPUClass),
 274        .class_init = alpha_cpu_class_init,
 275    },
 276    DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev4", ev4_cpu_initfn),
 277    DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev5", ev5_cpu_initfn),
 278    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev5"), "ev56", ev56_cpu_initfn),
 279    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev56"), "pca56",
 280                          pca56_cpu_initfn),
 281    DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev6", ev6_cpu_initfn),
 282    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev6"), "ev67", ev67_cpu_initfn),
 283    DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev67"), "ev68", NULL),
 284};
 285
 286DEFINE_TYPES(alpha_cpu_type_infos)
 287