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/translation-block.h" 27 #include "exec/target_page.h" 28 #include "accel/tcg/cpu-ops.h" 29 #include "fpu/softfloat.h" 30 31 32 static void alpha_cpu_set_pc(CPUState *cs, vaddr value) 33 { 34 CPUAlphaState *env = cpu_env(cs); 35 env->pc = value; 36 } 37 38 static vaddr alpha_cpu_get_pc(CPUState *cs) 39 { 40 CPUAlphaState *env = cpu_env(cs); 41 return env->pc; 42 } 43 44 void cpu_get_tb_cpu_state(CPUAlphaState *env, vaddr *pc, 45 uint64_t *cs_base, uint32_t *pflags) 46 { 47 *pc = env->pc; 48 *cs_base = 0; 49 *pflags = env->flags & ENV_FLAG_TB_MASK; 50 #ifdef CONFIG_USER_ONLY 51 *pflags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; 52 #endif 53 } 54 55 static void alpha_cpu_synchronize_from_tb(CPUState *cs, 56 const TranslationBlock *tb) 57 { 58 /* The program counter is always up to date with CF_PCREL. */ 59 if (!(tb_cflags(tb) & CF_PCREL)) { 60 CPUAlphaState *env = cpu_env(cs); 61 env->pc = tb->pc; 62 } 63 } 64 65 static void alpha_restore_state_to_opc(CPUState *cs, 66 const TranslationBlock *tb, 67 const uint64_t *data) 68 { 69 CPUAlphaState *env = cpu_env(cs); 70 71 if (tb_cflags(tb) & CF_PCREL) { 72 env->pc = (env->pc & TARGET_PAGE_MASK) | data[0]; 73 } else { 74 env->pc = data[0]; 75 } 76 } 77 78 #ifndef CONFIG_USER_ONLY 79 static bool alpha_cpu_has_work(CPUState *cs) 80 { 81 /* Here we are checking to see if the CPU should wake up from HALT. 82 We will have gotten into this state only for WTINT from PALmode. */ 83 /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU 84 asleep even if (some) interrupts have been asserted. For now, 85 assume that if a CPU really wants to stay asleep, it will mask 86 interrupts at the chipset level, which will prevent these bits 87 from being set in the first place. */ 88 return cs->interrupt_request & (CPU_INTERRUPT_HARD 89 | CPU_INTERRUPT_TIMER 90 | CPU_INTERRUPT_SMP 91 | CPU_INTERRUPT_MCHK); 92 } 93 #endif /* !CONFIG_USER_ONLY */ 94 95 static int alpha_cpu_mmu_index(CPUState *cs, bool ifetch) 96 { 97 return alpha_env_mmu_index(cpu_env(cs)); 98 } 99 100 static void alpha_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) 101 { 102 info->endian = BFD_ENDIAN_LITTLE; 103 info->mach = bfd_mach_alpha_ev6; 104 info->print_insn = print_insn_alpha; 105 } 106 107 static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) 108 { 109 CPUState *cs = CPU(dev); 110 AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev); 111 Error *local_err = NULL; 112 113 #ifndef CONFIG_USER_ONLY 114 /* Use pc-relative instructions in system-mode */ 115 cs->tcg_cflags |= CF_PCREL; 116 #endif 117 118 cpu_exec_realizefn(cs, &local_err); 119 if (local_err != NULL) { 120 error_propagate(errp, local_err); 121 return; 122 } 123 124 qemu_init_vcpu(cs); 125 126 acc->parent_realize(dev, errp); 127 } 128 129 /* Models */ 130 typedef struct AlphaCPUAlias { 131 const char *alias; 132 const char *typename; 133 } AlphaCPUAlias; 134 135 static const AlphaCPUAlias alpha_cpu_aliases[] = { 136 { "21064", ALPHA_CPU_TYPE_NAME("ev4") }, 137 { "21164", ALPHA_CPU_TYPE_NAME("ev5") }, 138 { "21164a", ALPHA_CPU_TYPE_NAME("ev56") }, 139 { "21164pc", ALPHA_CPU_TYPE_NAME("pca56") }, 140 { "21264", ALPHA_CPU_TYPE_NAME("ev6") }, 141 { "21264a", ALPHA_CPU_TYPE_NAME("ev67") }, 142 }; 143 144 static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model) 145 { 146 ObjectClass *oc; 147 char *typename; 148 int i; 149 150 oc = object_class_by_name(cpu_model); 151 if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL) { 152 return oc; 153 } 154 155 for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) { 156 if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) { 157 oc = object_class_by_name(alpha_cpu_aliases[i].typename); 158 assert(oc != NULL && !object_class_is_abstract(oc)); 159 return oc; 160 } 161 } 162 163 typename = g_strdup_printf(ALPHA_CPU_TYPE_NAME("%s"), cpu_model); 164 oc = object_class_by_name(typename); 165 g_free(typename); 166 167 return oc; 168 } 169 170 static void ev4_cpu_initfn(Object *obj) 171 { 172 cpu_env(CPU(obj))->implver = IMPLVER_2106x; 173 } 174 175 static void ev5_cpu_initfn(Object *obj) 176 { 177 cpu_env(CPU(obj))->implver = IMPLVER_21164; 178 } 179 180 static void ev56_cpu_initfn(Object *obj) 181 { 182 cpu_env(CPU(obj))->amask |= AMASK_BWX; 183 } 184 185 static void pca56_cpu_initfn(Object *obj) 186 { 187 cpu_env(CPU(obj))->amask |= AMASK_MVI; 188 } 189 190 static void ev6_cpu_initfn(Object *obj) 191 { 192 CPUAlphaState *env = cpu_env(CPU(obj)); 193 194 env->implver = IMPLVER_21264; 195 env->amask = AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP; 196 } 197 198 static void ev67_cpu_initfn(Object *obj) 199 { 200 cpu_env(CPU(obj))->amask |= AMASK_CIX | AMASK_PREFETCH; 201 } 202 203 static void alpha_cpu_initfn(Object *obj) 204 { 205 CPUAlphaState *env = cpu_env(CPU(obj)); 206 207 /* TODO all this should be done in reset, not init */ 208 209 env->lock_addr = -1; 210 211 /* 212 * TODO: this is incorrect. The Alpha Architecture Handbook version 4 213 * describes NaN propagation in section 4.7.10.4. We should prefer 214 * the operand in Fb (whether it is a QNaN or an SNaN), then the 215 * operand in Fa. That is float_2nan_prop_ba. 216 */ 217 set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status); 218 /* Default NaN: sign bit clear, msb frac bit set */ 219 set_float_default_nan_pattern(0b01000000, &env->fp_status); 220 /* 221 * TODO: this is incorrect. The Alpha Architecture Handbook version 4 222 * section 4.7.7.11 says that we flush to zero for underflow cases, so 223 * this should be float_ftz_after_rounding to match the 224 * tininess_after_rounding (which is specified in section 4.7.5). 225 */ 226 set_float_ftz_detection(float_ftz_before_rounding, &env->fp_status); 227 #if defined(CONFIG_USER_ONLY) 228 env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN; 229 cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD 230 | FPCR_UNFD | FPCR_INED | FPCR_DNOD 231 | FPCR_DYN_NORMAL) << 32); 232 #else 233 env->flags = ENV_FLAG_PAL_MODE | ENV_FLAG_FEN; 234 #endif 235 } 236 237 #ifndef CONFIG_USER_ONLY 238 #include "hw/core/sysemu-cpu-ops.h" 239 240 static const struct SysemuCPUOps alpha_sysemu_ops = { 241 .has_work = alpha_cpu_has_work, 242 .get_phys_page_debug = alpha_cpu_get_phys_page_debug, 243 }; 244 #endif 245 246 static const TCGCPUOps alpha_tcg_ops = { 247 /* Alpha processors have a weak memory model */ 248 .guest_default_memory_order = 0, 249 .mttcg_supported = true, 250 251 .initialize = alpha_translate_init, 252 .translate_code = alpha_translate_code, 253 .synchronize_from_tb = alpha_cpu_synchronize_from_tb, 254 .restore_state_to_opc = alpha_restore_state_to_opc, 255 .mmu_index = alpha_cpu_mmu_index, 256 257 #ifdef CONFIG_USER_ONLY 258 .record_sigsegv = alpha_cpu_record_sigsegv, 259 .record_sigbus = alpha_cpu_record_sigbus, 260 #else 261 .tlb_fill = alpha_cpu_tlb_fill, 262 .cpu_exec_interrupt = alpha_cpu_exec_interrupt, 263 .cpu_exec_halt = alpha_cpu_has_work, 264 .cpu_exec_reset = cpu_reset, 265 .do_interrupt = alpha_cpu_do_interrupt, 266 .do_transaction_failed = alpha_cpu_do_transaction_failed, 267 .do_unaligned_access = alpha_cpu_do_unaligned_access, 268 #endif /* !CONFIG_USER_ONLY */ 269 }; 270 271 static void alpha_cpu_class_init(ObjectClass *oc, const void *data) 272 { 273 DeviceClass *dc = DEVICE_CLASS(oc); 274 CPUClass *cc = CPU_CLASS(oc); 275 AlphaCPUClass *acc = ALPHA_CPU_CLASS(oc); 276 277 device_class_set_parent_realize(dc, alpha_cpu_realizefn, 278 &acc->parent_realize); 279 280 cc->class_by_name = alpha_cpu_class_by_name; 281 cc->dump_state = alpha_cpu_dump_state; 282 cc->set_pc = alpha_cpu_set_pc; 283 cc->get_pc = alpha_cpu_get_pc; 284 cc->gdb_read_register = alpha_cpu_gdb_read_register; 285 cc->gdb_write_register = alpha_cpu_gdb_write_register; 286 #ifndef CONFIG_USER_ONLY 287 dc->vmsd = &vmstate_alpha_cpu; 288 cc->sysemu_ops = &alpha_sysemu_ops; 289 #endif 290 cc->disas_set_info = alpha_cpu_disas_set_info; 291 292 cc->tcg_ops = &alpha_tcg_ops; 293 cc->gdb_num_core_regs = 67; 294 } 295 296 #define DEFINE_ALPHA_CPU_TYPE(base_type, cpu_model, initfn) \ 297 { \ 298 .parent = base_type, \ 299 .instance_init = initfn, \ 300 .name = ALPHA_CPU_TYPE_NAME(cpu_model), \ 301 } 302 303 static const TypeInfo alpha_cpu_type_infos[] = { 304 { 305 .name = TYPE_ALPHA_CPU, 306 .parent = TYPE_CPU, 307 .instance_size = sizeof(AlphaCPU), 308 .instance_align = __alignof(AlphaCPU), 309 .instance_init = alpha_cpu_initfn, 310 .abstract = true, 311 .class_size = sizeof(AlphaCPUClass), 312 .class_init = alpha_cpu_class_init, 313 }, 314 DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev4", ev4_cpu_initfn), 315 DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev5", ev5_cpu_initfn), 316 DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev5"), "ev56", ev56_cpu_initfn), 317 DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev56"), "pca56", 318 pca56_cpu_initfn), 319 DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev6", ev6_cpu_initfn), 320 DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev6"), "ev67", ev67_cpu_initfn), 321 DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev67"), "ev68", NULL), 322 }; 323 324 DEFINE_TYPES(alpha_cpu_type_infos) 325