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