xref: /qemu/target/m68k/cpu.c (revision b15c0f7d)
1 /*
2  * QEMU Motorola 68k CPU
3  *
4  * Copyright (c) 2012 SUSE LINUX Products GmbH
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see
18  * <http://www.gnu.org/licenses/lgpl-2.1.html>
19  */
20 
21 #include "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "cpu.h"
24 #include "qemu-common.h"
25 #include "migration/vmstate.h"
26 #include "fpu/softfloat.h"
27 
28 static void m68k_cpu_set_pc(CPUState *cs, vaddr value)
29 {
30     M68kCPU *cpu = M68K_CPU(cs);
31 
32     cpu->env.pc = value;
33 }
34 
35 static bool m68k_cpu_has_work(CPUState *cs)
36 {
37     return cs->interrupt_request & CPU_INTERRUPT_HARD;
38 }
39 
40 static void m68k_set_feature(CPUM68KState *env, int feature)
41 {
42     env->features |= (1u << feature);
43 }
44 
45 /* CPUClass::reset() */
46 static void m68k_cpu_reset(CPUState *s)
47 {
48     M68kCPU *cpu = M68K_CPU(s);
49     M68kCPUClass *mcc = M68K_CPU_GET_CLASS(cpu);
50     CPUM68KState *env = &cpu->env;
51     floatx80 nan = floatx80_default_nan(NULL);
52     int i;
53 
54     mcc->parent_reset(s);
55 
56     memset(env, 0, offsetof(CPUM68KState, end_reset_fields));
57 #ifdef CONFIG_SOFTMMU
58     cpu_m68k_set_sr(env, SR_S | SR_I);
59 #else
60     cpu_m68k_set_sr(env, 0);
61 #endif
62     for (i = 0; i < 8; i++) {
63         env->fregs[i].d = nan;
64     }
65     cpu_m68k_set_fpcr(env, 0);
66     env->fpsr = 0;
67 
68     /* TODO: We should set PC from the interrupt vector.  */
69     env->pc = 0;
70 }
71 
72 static void m68k_cpu_disas_set_info(CPUState *s, disassemble_info *info)
73 {
74     M68kCPU *cpu = M68K_CPU(s);
75     CPUM68KState *env = &cpu->env;
76     info->print_insn = print_insn_m68k;
77     if (m68k_feature(env, M68K_FEATURE_M68000)) {
78         info->mach = bfd_mach_m68040;
79     }
80 }
81 
82 /* CPU models */
83 
84 static ObjectClass *m68k_cpu_class_by_name(const char *cpu_model)
85 {
86     ObjectClass *oc;
87     char *typename;
88 
89     typename = g_strdup_printf(M68K_CPU_TYPE_NAME("%s"), cpu_model);
90     oc = object_class_by_name(typename);
91     g_free(typename);
92     if (oc != NULL && (object_class_dynamic_cast(oc, TYPE_M68K_CPU) == NULL ||
93                        object_class_is_abstract(oc))) {
94         return NULL;
95     }
96     return oc;
97 }
98 
99 static void m5206_cpu_initfn(Object *obj)
100 {
101     M68kCPU *cpu = M68K_CPU(obj);
102     CPUM68KState *env = &cpu->env;
103 
104     m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
105 }
106 
107 static void m68000_cpu_initfn(Object *obj)
108 {
109     M68kCPU *cpu = M68K_CPU(obj);
110     CPUM68KState *env = &cpu->env;
111 
112     m68k_set_feature(env, M68K_FEATURE_M68000);
113     m68k_set_feature(env, M68K_FEATURE_USP);
114     m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
115     m68k_set_feature(env, M68K_FEATURE_MOVEP);
116 }
117 
118 static void m68020_cpu_initfn(Object *obj)
119 {
120     M68kCPU *cpu = M68K_CPU(obj);
121     CPUM68KState *env = &cpu->env;
122 
123     m68k_set_feature(env, M68K_FEATURE_M68000);
124     m68k_set_feature(env, M68K_FEATURE_USP);
125     m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
126     m68k_set_feature(env, M68K_FEATURE_QUAD_MULDIV);
127     m68k_set_feature(env, M68K_FEATURE_BRAL);
128     m68k_set_feature(env, M68K_FEATURE_BCCL);
129     m68k_set_feature(env, M68K_FEATURE_BITFIELD);
130     m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
131     m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
132     m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV);
133     m68k_set_feature(env, M68K_FEATURE_FPU);
134     m68k_set_feature(env, M68K_FEATURE_CAS);
135     m68k_set_feature(env, M68K_FEATURE_BKPT);
136     m68k_set_feature(env, M68K_FEATURE_RTD);
137     m68k_set_feature(env, M68K_FEATURE_CHK2);
138     m68k_set_feature(env, M68K_FEATURE_MOVEP);
139 }
140 #define m68030_cpu_initfn m68020_cpu_initfn
141 
142 static void m68040_cpu_initfn(Object *obj)
143 {
144     M68kCPU *cpu = M68K_CPU(obj);
145     CPUM68KState *env = &cpu->env;
146 
147     m68020_cpu_initfn(obj);
148     m68k_set_feature(env, M68K_FEATURE_M68040);
149 }
150 
151 static void m68060_cpu_initfn(Object *obj)
152 {
153     M68kCPU *cpu = M68K_CPU(obj);
154     CPUM68KState *env = &cpu->env;
155 
156     m68k_set_feature(env, M68K_FEATURE_M68000);
157     m68k_set_feature(env, M68K_FEATURE_USP);
158     m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
159     m68k_set_feature(env, M68K_FEATURE_BRAL);
160     m68k_set_feature(env, M68K_FEATURE_BCCL);
161     m68k_set_feature(env, M68K_FEATURE_BITFIELD);
162     m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
163     m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
164     m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV);
165     m68k_set_feature(env, M68K_FEATURE_FPU);
166     m68k_set_feature(env, M68K_FEATURE_CAS);
167     m68k_set_feature(env, M68K_FEATURE_BKPT);
168     m68k_set_feature(env, M68K_FEATURE_RTD);
169     m68k_set_feature(env, M68K_FEATURE_CHK2);
170 }
171 
172 static void m5208_cpu_initfn(Object *obj)
173 {
174     M68kCPU *cpu = M68K_CPU(obj);
175     CPUM68KState *env = &cpu->env;
176 
177     m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
178     m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
179     m68k_set_feature(env, M68K_FEATURE_BRAL);
180     m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
181     m68k_set_feature(env, M68K_FEATURE_USP);
182 }
183 
184 static void cfv4e_cpu_initfn(Object *obj)
185 {
186     M68kCPU *cpu = M68K_CPU(obj);
187     CPUM68KState *env = &cpu->env;
188 
189     m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
190     m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
191     m68k_set_feature(env, M68K_FEATURE_BRAL);
192     m68k_set_feature(env, M68K_FEATURE_CF_FPU);
193     m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
194     m68k_set_feature(env, M68K_FEATURE_USP);
195 }
196 
197 static void any_cpu_initfn(Object *obj)
198 {
199     M68kCPU *cpu = M68K_CPU(obj);
200     CPUM68KState *env = &cpu->env;
201 
202     m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
203     m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
204     m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
205     m68k_set_feature(env, M68K_FEATURE_BRAL);
206     m68k_set_feature(env, M68K_FEATURE_CF_FPU);
207     /* MAC and EMAC are mututally exclusive, so pick EMAC.
208        It's mostly backwards compatible.  */
209     m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
210     m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
211     m68k_set_feature(env, M68K_FEATURE_USP);
212     m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
213     m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
214 }
215 
216 static void m68k_cpu_realizefn(DeviceState *dev, Error **errp)
217 {
218     CPUState *cs = CPU(dev);
219     M68kCPU *cpu = M68K_CPU(dev);
220     M68kCPUClass *mcc = M68K_CPU_GET_CLASS(dev);
221     Error *local_err = NULL;
222 
223     register_m68k_insns(&cpu->env);
224 
225     cpu_exec_realizefn(cs, &local_err);
226     if (local_err != NULL) {
227         error_propagate(errp, local_err);
228         return;
229     }
230 
231     m68k_cpu_init_gdb(cpu);
232 
233     cpu_reset(cs);
234     qemu_init_vcpu(cs);
235 
236     mcc->parent_realize(dev, errp);
237 }
238 
239 static void m68k_cpu_initfn(Object *obj)
240 {
241     CPUState *cs = CPU(obj);
242     M68kCPU *cpu = M68K_CPU(obj);
243     CPUM68KState *env = &cpu->env;
244 
245     cs->env_ptr = env;
246 }
247 
248 static const VMStateDescription vmstate_m68k_cpu = {
249     .name = "cpu",
250     .unmigratable = 1,
251 };
252 
253 static void m68k_cpu_class_init(ObjectClass *c, void *data)
254 {
255     M68kCPUClass *mcc = M68K_CPU_CLASS(c);
256     CPUClass *cc = CPU_CLASS(c);
257     DeviceClass *dc = DEVICE_CLASS(c);
258 
259     device_class_set_parent_realize(dc, m68k_cpu_realizefn,
260                                     &mcc->parent_realize);
261     mcc->parent_reset = cc->reset;
262     cc->reset = m68k_cpu_reset;
263 
264     cc->class_by_name = m68k_cpu_class_by_name;
265     cc->has_work = m68k_cpu_has_work;
266     cc->do_interrupt = m68k_cpu_do_interrupt;
267     cc->cpu_exec_interrupt = m68k_cpu_exec_interrupt;
268     cc->dump_state = m68k_cpu_dump_state;
269     cc->set_pc = m68k_cpu_set_pc;
270     cc->gdb_read_register = m68k_cpu_gdb_read_register;
271     cc->gdb_write_register = m68k_cpu_gdb_write_register;
272     cc->tlb_fill = m68k_cpu_tlb_fill;
273 #if defined(CONFIG_SOFTMMU)
274     cc->do_transaction_failed = m68k_cpu_transaction_failed;
275     cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
276 #endif
277     cc->disas_set_info = m68k_cpu_disas_set_info;
278     cc->tcg_initialize = m68k_tcg_init;
279 
280     cc->gdb_num_core_regs = 18;
281     cc->gdb_core_xml_file = "cf-core.xml";
282 
283     dc->vmsd = &vmstate_m68k_cpu;
284 }
285 
286 #define DEFINE_M68K_CPU_TYPE(cpu_model, initfn) \
287     {                                           \
288         .name = M68K_CPU_TYPE_NAME(cpu_model),  \
289         .instance_init = initfn,                \
290         .parent = TYPE_M68K_CPU,                \
291     }
292 
293 static const TypeInfo m68k_cpus_type_infos[] = {
294     { /* base class should be registered first */
295         .name = TYPE_M68K_CPU,
296         .parent = TYPE_CPU,
297         .instance_size = sizeof(M68kCPU),
298         .instance_init = m68k_cpu_initfn,
299         .abstract = true,
300         .class_size = sizeof(M68kCPUClass),
301         .class_init = m68k_cpu_class_init,
302     },
303     DEFINE_M68K_CPU_TYPE("m68000", m68000_cpu_initfn),
304     DEFINE_M68K_CPU_TYPE("m68020", m68020_cpu_initfn),
305     DEFINE_M68K_CPU_TYPE("m68030", m68030_cpu_initfn),
306     DEFINE_M68K_CPU_TYPE("m68040", m68040_cpu_initfn),
307     DEFINE_M68K_CPU_TYPE("m68060", m68060_cpu_initfn),
308     DEFINE_M68K_CPU_TYPE("m5206", m5206_cpu_initfn),
309     DEFINE_M68K_CPU_TYPE("m5208", m5208_cpu_initfn),
310     DEFINE_M68K_CPU_TYPE("cfv4e", cfv4e_cpu_initfn),
311     DEFINE_M68K_CPU_TYPE("any", any_cpu_initfn),
312 };
313 
314 DEFINE_TYPES(m68k_cpus_type_infos)
315