xref: /openbmc/qemu/target/alpha/cpu.c (revision f15f7273ea55472d5904c53566c82369d81214c1)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  * QEMU Alpha CPU
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  * Copyright (c) 2007 Jocelyn Mayer
5fcf5ef2aSThomas Huth  * Copyright (c) 2012 SUSE LINUX Products GmbH
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
10fcf5ef2aSThomas Huth  * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see
19fcf5ef2aSThomas Huth  * <http://www.gnu.org/licenses/lgpl-2.1.html>
20fcf5ef2aSThomas Huth  */
21fcf5ef2aSThomas Huth 
22fcf5ef2aSThomas Huth #include "qemu/osdep.h"
23fcf5ef2aSThomas Huth #include "qapi/error.h"
240442428aSMarkus Armbruster #include "qemu/qemu-print.h"
25fcf5ef2aSThomas Huth #include "cpu.h"
26fcf5ef2aSThomas Huth #include "exec/exec-all.h"
27*8403a501SPeter Maydell #include "fpu/softfloat.h"
28fcf5ef2aSThomas Huth 
29fcf5ef2aSThomas Huth 
alpha_cpu_set_pc(CPUState * cs,vaddr value)30fcf5ef2aSThomas Huth static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
31fcf5ef2aSThomas Huth {
32ab709f13SRichard Henderson     CPUAlphaState *env = cpu_env(cs);
33ab709f13SRichard Henderson     env->pc = value;
34fcf5ef2aSThomas Huth }
35fcf5ef2aSThomas Huth 
alpha_cpu_get_pc(CPUState * cs)36e4fdf9dfSRichard Henderson static vaddr alpha_cpu_get_pc(CPUState *cs)
37e4fdf9dfSRichard Henderson {
38ab709f13SRichard Henderson     CPUAlphaState *env = cpu_env(cs);
39ab709f13SRichard Henderson     return env->pc;
40e4fdf9dfSRichard Henderson }
41e4fdf9dfSRichard Henderson 
alpha_cpu_synchronize_from_tb(CPUState * cs,const TranslationBlock * tb)4223bb0863SRichard Henderson static void alpha_cpu_synchronize_from_tb(CPUState *cs,
4323bb0863SRichard Henderson                                           const TranslationBlock *tb)
4423bb0863SRichard Henderson {
4523bb0863SRichard Henderson     /* The program counter is always up to date with CF_PCREL. */
4623bb0863SRichard Henderson     if (!(tb_cflags(tb) & CF_PCREL)) {
4723bb0863SRichard Henderson         CPUAlphaState *env = cpu_env(cs);
4823bb0863SRichard Henderson         env->pc = tb->pc;
4923bb0863SRichard Henderson     }
5023bb0863SRichard Henderson }
5123bb0863SRichard Henderson 
alpha_restore_state_to_opc(CPUState * cs,const TranslationBlock * tb,const uint64_t * data)52c0cd068fSRichard Henderson static void alpha_restore_state_to_opc(CPUState *cs,
53c0cd068fSRichard Henderson                                        const TranslationBlock *tb,
54c0cd068fSRichard Henderson                                        const uint64_t *data)
55c0cd068fSRichard Henderson {
56ab709f13SRichard Henderson     CPUAlphaState *env = cpu_env(cs);
5723bb0863SRichard Henderson 
5823bb0863SRichard Henderson     if (tb_cflags(tb) & CF_PCREL) {
5923bb0863SRichard Henderson         env->pc = (env->pc & TARGET_PAGE_MASK) | data[0];
6023bb0863SRichard Henderson     } else {
61ab709f13SRichard Henderson         env->pc = data[0];
62c0cd068fSRichard Henderson     }
6323bb0863SRichard Henderson }
64e4fdf9dfSRichard Henderson 
alpha_cpu_has_work(CPUState * cs)65fcf5ef2aSThomas Huth static bool alpha_cpu_has_work(CPUState *cs)
66fcf5ef2aSThomas Huth {
67fcf5ef2aSThomas Huth     /* Here we are checking to see if the CPU should wake up from HALT.
68fcf5ef2aSThomas Huth        We will have gotten into this state only for WTINT from PALmode.  */
69fcf5ef2aSThomas Huth     /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU
70fcf5ef2aSThomas Huth        asleep even if (some) interrupts have been asserted.  For now,
71fcf5ef2aSThomas Huth        assume that if a CPU really wants to stay asleep, it will mask
72fcf5ef2aSThomas Huth        interrupts at the chipset level, which will prevent these bits
73fcf5ef2aSThomas Huth        from being set in the first place.  */
74fcf5ef2aSThomas Huth     return cs->interrupt_request & (CPU_INTERRUPT_HARD
75fcf5ef2aSThomas Huth                                     | CPU_INTERRUPT_TIMER
76fcf5ef2aSThomas Huth                                     | CPU_INTERRUPT_SMP
77fcf5ef2aSThomas Huth                                     | CPU_INTERRUPT_MCHK);
78fcf5ef2aSThomas Huth }
79fcf5ef2aSThomas Huth 
alpha_cpu_mmu_index(CPUState * cs,bool ifetch)809d684790SRichard Henderson static int alpha_cpu_mmu_index(CPUState *cs, bool ifetch)
819d684790SRichard Henderson {
829d684790SRichard Henderson     return alpha_env_mmu_index(cpu_env(cs));
839d684790SRichard Henderson }
849d684790SRichard Henderson 
alpha_cpu_disas_set_info(CPUState * cpu,disassemble_info * info)85fcf5ef2aSThomas Huth static void alpha_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
86fcf5ef2aSThomas Huth {
87fcf5ef2aSThomas Huth     info->mach = bfd_mach_alpha_ev6;
88fcf5ef2aSThomas Huth     info->print_insn = print_insn_alpha;
89fcf5ef2aSThomas Huth }
90fcf5ef2aSThomas Huth 
alpha_cpu_realizefn(DeviceState * dev,Error ** errp)91fcf5ef2aSThomas Huth static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)
92fcf5ef2aSThomas Huth {
93fcf5ef2aSThomas Huth     CPUState *cs = CPU(dev);
94fcf5ef2aSThomas Huth     AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev);
95fcf5ef2aSThomas Huth     Error *local_err = NULL;
96fcf5ef2aSThomas Huth 
9723bb0863SRichard Henderson #ifndef CONFIG_USER_ONLY
9823bb0863SRichard Henderson     /* Use pc-relative instructions in system-mode */
9923bb0863SRichard Henderson     cs->tcg_cflags |= CF_PCREL;
10023bb0863SRichard Henderson #endif
10123bb0863SRichard Henderson 
102fcf5ef2aSThomas Huth     cpu_exec_realizefn(cs, &local_err);
103fcf5ef2aSThomas Huth     if (local_err != NULL) {
104fcf5ef2aSThomas Huth         error_propagate(errp, local_err);
105fcf5ef2aSThomas Huth         return;
106fcf5ef2aSThomas Huth     }
107fcf5ef2aSThomas Huth 
108fcf5ef2aSThomas Huth     qemu_init_vcpu(cs);
109fcf5ef2aSThomas Huth 
110fcf5ef2aSThomas Huth     acc->parent_realize(dev, errp);
111fcf5ef2aSThomas Huth }
112fcf5ef2aSThomas Huth 
113fcf5ef2aSThomas Huth /* Models */
114fcf5ef2aSThomas Huth typedef struct AlphaCPUAlias {
115fcf5ef2aSThomas Huth     const char *alias;
116fcf5ef2aSThomas Huth     const char *typename;
117fcf5ef2aSThomas Huth } AlphaCPUAlias;
118fcf5ef2aSThomas Huth 
119fcf5ef2aSThomas Huth static const AlphaCPUAlias alpha_cpu_aliases[] = {
12073a25e83SIgor Mammedov     { "21064",   ALPHA_CPU_TYPE_NAME("ev4") },
12173a25e83SIgor Mammedov     { "21164",   ALPHA_CPU_TYPE_NAME("ev5") },
12273a25e83SIgor Mammedov     { "21164a",  ALPHA_CPU_TYPE_NAME("ev56") },
12373a25e83SIgor Mammedov     { "21164pc", ALPHA_CPU_TYPE_NAME("pca56") },
12473a25e83SIgor Mammedov     { "21264",   ALPHA_CPU_TYPE_NAME("ev6") },
12573a25e83SIgor Mammedov     { "21264a",  ALPHA_CPU_TYPE_NAME("ev67") },
126fcf5ef2aSThomas Huth };
127fcf5ef2aSThomas Huth 
alpha_cpu_class_by_name(const char * cpu_model)128fcf5ef2aSThomas Huth static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model)
129fcf5ef2aSThomas Huth {
1308301ea44SPhilippe Mathieu-Daudé     ObjectClass *oc;
131fcf5ef2aSThomas Huth     char *typename;
132fcf5ef2aSThomas Huth     int i;
133fcf5ef2aSThomas Huth 
134fcf5ef2aSThomas Huth     oc = object_class_by_name(cpu_model);
1353a9d0d7bSPhilippe Mathieu-Daudé     if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL) {
136fcf5ef2aSThomas Huth         return oc;
137fcf5ef2aSThomas Huth     }
138fcf5ef2aSThomas Huth 
139fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) {
140fcf5ef2aSThomas Huth         if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) {
141fcf5ef2aSThomas Huth             oc = object_class_by_name(alpha_cpu_aliases[i].typename);
142fcf5ef2aSThomas Huth             assert(oc != NULL && !object_class_is_abstract(oc));
143fcf5ef2aSThomas Huth             return oc;
144fcf5ef2aSThomas Huth         }
145fcf5ef2aSThomas Huth     }
146fcf5ef2aSThomas Huth 
14773a25e83SIgor Mammedov     typename = g_strdup_printf(ALPHA_CPU_TYPE_NAME("%s"), cpu_model);
148fcf5ef2aSThomas Huth     oc = object_class_by_name(typename);
149fcf5ef2aSThomas Huth     g_free(typename);
150fcf5ef2aSThomas Huth 
15182a3d1f8SIgor Mammedov     return oc;
152fcf5ef2aSThomas Huth }
153fcf5ef2aSThomas Huth 
ev4_cpu_initfn(Object * obj)154fcf5ef2aSThomas Huth static void ev4_cpu_initfn(Object *obj)
155fcf5ef2aSThomas Huth {
15650cb36ceSPhilippe Mathieu-Daudé     cpu_env(CPU(obj))->implver = IMPLVER_2106x;
157fcf5ef2aSThomas Huth }
158fcf5ef2aSThomas Huth 
ev5_cpu_initfn(Object * obj)159fcf5ef2aSThomas Huth static void ev5_cpu_initfn(Object *obj)
160fcf5ef2aSThomas Huth {
16150cb36ceSPhilippe Mathieu-Daudé     cpu_env(CPU(obj))->implver = IMPLVER_21164;
162fcf5ef2aSThomas Huth }
163fcf5ef2aSThomas Huth 
ev56_cpu_initfn(Object * obj)164fcf5ef2aSThomas Huth static void ev56_cpu_initfn(Object *obj)
165fcf5ef2aSThomas Huth {
16650cb36ceSPhilippe Mathieu-Daudé     cpu_env(CPU(obj))->amask |= AMASK_BWX;
167fcf5ef2aSThomas Huth }
168fcf5ef2aSThomas Huth 
pca56_cpu_initfn(Object * obj)169fcf5ef2aSThomas Huth static void pca56_cpu_initfn(Object *obj)
170fcf5ef2aSThomas Huth {
17150cb36ceSPhilippe Mathieu-Daudé     cpu_env(CPU(obj))->amask |= AMASK_MVI;
172fcf5ef2aSThomas Huth }
173fcf5ef2aSThomas Huth 
ev6_cpu_initfn(Object * obj)174fcf5ef2aSThomas Huth static void ev6_cpu_initfn(Object *obj)
175fcf5ef2aSThomas Huth {
17650cb36ceSPhilippe Mathieu-Daudé     CPUAlphaState *env = cpu_env(CPU(obj));
177fcf5ef2aSThomas Huth 
178fcf5ef2aSThomas Huth     env->implver = IMPLVER_21264;
179fcf5ef2aSThomas Huth     env->amask = AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP;
180fcf5ef2aSThomas Huth }
181fcf5ef2aSThomas Huth 
ev67_cpu_initfn(Object * obj)182fcf5ef2aSThomas Huth static void ev67_cpu_initfn(Object *obj)
183fcf5ef2aSThomas Huth {
18450cb36ceSPhilippe Mathieu-Daudé     cpu_env(CPU(obj))->amask |= AMASK_CIX | AMASK_PREFETCH;
185fcf5ef2aSThomas Huth }
186fcf5ef2aSThomas Huth 
alpha_cpu_initfn(Object * obj)187fcf5ef2aSThomas Huth static void alpha_cpu_initfn(Object *obj)
188fcf5ef2aSThomas Huth {
18950cb36ceSPhilippe Mathieu-Daudé     CPUAlphaState *env = cpu_env(CPU(obj));
190fcf5ef2aSThomas Huth 
191*8403a501SPeter Maydell     /* TODO all this should be done in reset, not init */
192*8403a501SPeter Maydell 
193bcd2625dSRichard Henderson     env->lock_addr = -1;
194*8403a501SPeter Maydell 
195*8403a501SPeter Maydell     /*
196*8403a501SPeter Maydell      * TODO: this is incorrect. The Alpha Architecture Handbook version 4
197*8403a501SPeter Maydell      * describes NaN propagation in section 4.7.10.4. We should prefer
198*8403a501SPeter Maydell      * the operand in Fb (whether it is a QNaN or an SNaN), then the
199*8403a501SPeter Maydell      * operand in Fa. That is float_2nan_prop_ba.
200*8403a501SPeter Maydell      */
201*8403a501SPeter Maydell     set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
202fcf5ef2aSThomas Huth #if defined(CONFIG_USER_ONLY)
203bcd2625dSRichard Henderson     env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
20429eb5280SRichard Henderson     cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
205fcf5ef2aSThomas Huth                                          | FPCR_UNFD | FPCR_INED | FPCR_DNOD
20629eb5280SRichard Henderson                                          | FPCR_DYN_NORMAL) << 32);
207bcd2625dSRichard Henderson #else
208bcd2625dSRichard Henderson     env->flags = ENV_FLAG_PAL_MODE | ENV_FLAG_FEN;
209fcf5ef2aSThomas Huth #endif
210fcf5ef2aSThomas Huth }
211fcf5ef2aSThomas Huth 
2128b80bd28SPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY
2138b80bd28SPhilippe Mathieu-Daudé #include "hw/core/sysemu-cpu-ops.h"
2148b80bd28SPhilippe Mathieu-Daudé 
2158b80bd28SPhilippe Mathieu-Daudé static const struct SysemuCPUOps alpha_sysemu_ops = {
21608928c6dSPhilippe Mathieu-Daudé     .get_phys_page_debug = alpha_cpu_get_phys_page_debug,
2178b80bd28SPhilippe Mathieu-Daudé };
2188b80bd28SPhilippe Mathieu-Daudé #endif
2198b80bd28SPhilippe Mathieu-Daudé 
22078271684SClaudio Fontana #include "hw/core/tcg-cpu-ops.h"
22178271684SClaudio Fontana 
2221764ad70SRichard Henderson static const TCGCPUOps alpha_tcg_ops = {
22378271684SClaudio Fontana     .initialize = alpha_translate_init,
22423bb0863SRichard Henderson     .synchronize_from_tb = alpha_cpu_synchronize_from_tb,
225c0cd068fSRichard Henderson     .restore_state_to_opc = alpha_restore_state_to_opc,
22678271684SClaudio Fontana 
22790113883SRichard Henderson #ifdef CONFIG_USER_ONLY
22890113883SRichard Henderson     .record_sigsegv = alpha_cpu_record_sigsegv,
229e7424abcSRichard Henderson     .record_sigbus = alpha_cpu_record_sigbus,
23090113883SRichard Henderson #else
23190113883SRichard Henderson     .tlb_fill = alpha_cpu_tlb_fill,
2329354e694SPhilippe Mathieu-Daudé     .cpu_exec_interrupt = alpha_cpu_exec_interrupt,
2334f7b1ecbSPeter Maydell     .cpu_exec_halt = alpha_cpu_has_work,
23478271684SClaudio Fontana     .do_interrupt = alpha_cpu_do_interrupt,
23578271684SClaudio Fontana     .do_transaction_failed = alpha_cpu_do_transaction_failed,
23678271684SClaudio Fontana     .do_unaligned_access = alpha_cpu_do_unaligned_access,
23778271684SClaudio Fontana #endif /* !CONFIG_USER_ONLY */
23878271684SClaudio Fontana };
23978271684SClaudio Fontana 
alpha_cpu_class_init(ObjectClass * oc,void * data)240fcf5ef2aSThomas Huth static void alpha_cpu_class_init(ObjectClass *oc, void *data)
241fcf5ef2aSThomas Huth {
242fcf5ef2aSThomas Huth     DeviceClass *dc = DEVICE_CLASS(oc);
243fcf5ef2aSThomas Huth     CPUClass *cc = CPU_CLASS(oc);
244fcf5ef2aSThomas Huth     AlphaCPUClass *acc = ALPHA_CPU_CLASS(oc);
245fcf5ef2aSThomas Huth 
246bf853881SPhilippe Mathieu-Daudé     device_class_set_parent_realize(dc, alpha_cpu_realizefn,
247bf853881SPhilippe Mathieu-Daudé                                     &acc->parent_realize);
248fcf5ef2aSThomas Huth 
249fcf5ef2aSThomas Huth     cc->class_by_name = alpha_cpu_class_by_name;
250fcf5ef2aSThomas Huth     cc->has_work = alpha_cpu_has_work;
2519d684790SRichard Henderson     cc->mmu_index = alpha_cpu_mmu_index;
252fcf5ef2aSThomas Huth     cc->dump_state = alpha_cpu_dump_state;
253fcf5ef2aSThomas Huth     cc->set_pc = alpha_cpu_set_pc;
254e4fdf9dfSRichard Henderson     cc->get_pc = alpha_cpu_get_pc;
255fcf5ef2aSThomas Huth     cc->gdb_read_register = alpha_cpu_gdb_read_register;
256fcf5ef2aSThomas Huth     cc->gdb_write_register = alpha_cpu_gdb_write_register;
257e41c9452SRichard Henderson #ifndef CONFIG_USER_ONLY
258fcf5ef2aSThomas Huth     dc->vmsd = &vmstate_alpha_cpu;
2598b80bd28SPhilippe Mathieu-Daudé     cc->sysemu_ops = &alpha_sysemu_ops;
260fcf5ef2aSThomas Huth #endif
261fcf5ef2aSThomas Huth     cc->disas_set_info = alpha_cpu_disas_set_info;
262fcf5ef2aSThomas Huth 
26378271684SClaudio Fontana     cc->tcg_ops = &alpha_tcg_ops;
264fcf5ef2aSThomas Huth     cc->gdb_num_core_regs = 67;
265fcf5ef2aSThomas Huth }
266fcf5ef2aSThomas Huth 
26773a25e83SIgor Mammedov #define DEFINE_ALPHA_CPU_TYPE(base_type, cpu_model, initfn) \
26873a25e83SIgor Mammedov      {                                                      \
26973a25e83SIgor Mammedov          .parent = base_type,                               \
27073a25e83SIgor Mammedov          .instance_init = initfn,                           \
27173a25e83SIgor Mammedov          .name = ALPHA_CPU_TYPE_NAME(cpu_model),            \
27273a25e83SIgor Mammedov      }
27373a25e83SIgor Mammedov 
27473a25e83SIgor Mammedov static const TypeInfo alpha_cpu_type_infos[] = {
27573a25e83SIgor Mammedov     {
276fcf5ef2aSThomas Huth         .name = TYPE_ALPHA_CPU,
277fcf5ef2aSThomas Huth         .parent = TYPE_CPU,
278fcf5ef2aSThomas Huth         .instance_size = sizeof(AlphaCPU),
279f669c992SRichard Henderson         .instance_align = __alignof(AlphaCPU),
280fcf5ef2aSThomas Huth         .instance_init = alpha_cpu_initfn,
281fcf5ef2aSThomas Huth         .abstract = true,
282fcf5ef2aSThomas Huth         .class_size = sizeof(AlphaCPUClass),
283fcf5ef2aSThomas Huth         .class_init = alpha_cpu_class_init,
28473a25e83SIgor Mammedov     },
28573a25e83SIgor Mammedov     DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev4", ev4_cpu_initfn),
28673a25e83SIgor Mammedov     DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev5", ev5_cpu_initfn),
28773a25e83SIgor Mammedov     DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev5"), "ev56", ev56_cpu_initfn),
28873a25e83SIgor Mammedov     DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev56"), "pca56",
28973a25e83SIgor Mammedov                           pca56_cpu_initfn),
29073a25e83SIgor Mammedov     DEFINE_ALPHA_CPU_TYPE(TYPE_ALPHA_CPU, "ev6", ev6_cpu_initfn),
29173a25e83SIgor Mammedov     DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev6"), "ev67", ev67_cpu_initfn),
29273a25e83SIgor Mammedov     DEFINE_ALPHA_CPU_TYPE(ALPHA_CPU_TYPE_NAME("ev67"), "ev68", NULL),
293fcf5ef2aSThomas Huth };
294fcf5ef2aSThomas Huth 
29573a25e83SIgor Mammedov DEFINE_TYPES(alpha_cpu_type_infos)
296