blob: 72c545149e9bb24e4c748f344205d23107c29de3 [file] [log] [blame]
Andreas Färberb9e7a232012-04-15 00:35:50 +02001/*
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
Peter Maydelld8416662016-01-26 18:17:23 +000021#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010022#include "qapi/error.h"
Andreas Färberb9e7a232012-04-15 00:35:50 +020023#include "cpu.h"
Andreas Färber087fe4f2013-01-20 19:53:28 +010024#include "migration/vmstate.h"
Alex Bennée24f91e82018-01-19 18:24:22 +000025#include "fpu/softfloat.h"
Andreas Färberb9e7a232012-04-15 00:35:50 +020026
Andreas Färbere7006042013-06-28 20:35:01 +020027static void m68k_cpu_set_pc(CPUState *cs, vaddr value)
28{
29 M68kCPU *cpu = M68K_CPU(cs);
30
31 cpu->env.pc = value;
32}
33
Andreas Färber8c2e1b02013-08-25 18:53:55 +020034static bool m68k_cpu_has_work(CPUState *cs)
35{
36 return cs->interrupt_request & CPU_INTERRUPT_HARD;
37}
38
Andreas Färber11150912012-04-15 03:30:10 +020039static void m68k_set_feature(CPUM68KState *env, int feature)
40{
41 env->features |= (1u << feature);
42}
43
Peter Maydell781c67c2020-03-03 10:05:11 +000044static void m68k_cpu_reset(DeviceState *dev)
Andreas Färberb9e7a232012-04-15 00:35:50 +020045{
Peter Maydell781c67c2020-03-03 10:05:11 +000046 CPUState *s = CPU(dev);
Andreas Färberb9e7a232012-04-15 00:35:50 +020047 M68kCPU *cpu = M68K_CPU(s);
48 M68kCPUClass *mcc = M68K_CPU_GET_CLASS(cpu);
49 CPUM68KState *env = &cpu->env;
Laurent Vivierf83311e2017-06-20 22:51:18 +020050 floatx80 nan = floatx80_default_nan(NULL);
Laurent Vivierf4a6ce52017-06-20 22:51:17 +020051 int i;
Andreas Färberb9e7a232012-04-15 00:35:50 +020052
Peter Maydell781c67c2020-03-03 10:05:11 +000053 mcc->parent_reset(dev);
Andreas Färberb9e7a232012-04-15 00:35:50 +020054
Alex Bennée1f5c00c2016-11-14 14:19:17 +000055 memset(env, 0, offsetof(CPUM68KState, end_reset_fields));
Laurent Vivier6e22b282018-01-04 02:29:12 +010056#ifdef CONFIG_SOFTMMU
57 cpu_m68k_set_sr(env, SR_S | SR_I);
58#else
59 cpu_m68k_set_sr(env, 0);
Andreas Färber11c19862012-04-15 00:59:50 +020060#endif
Laurent Vivierf4a6ce52017-06-20 22:51:17 +020061 for (i = 0; i < 8; i++) {
Laurent Vivierf83311e2017-06-20 22:51:18 +020062 env->fregs[i].d = nan;
Laurent Vivierf4a6ce52017-06-20 22:51:17 +020063 }
Laurent Vivierba624942017-06-20 22:51:20 +020064 cpu_m68k_set_fpcr(env, 0);
Laurent Vivierf4a6ce52017-06-20 22:51:17 +020065 env->fpsr = 0;
66
Andreas Färber11c19862012-04-15 00:59:50 +020067 /* TODO: We should set PC from the interrupt vector. */
68 env->pc = 0;
Andreas Färberb9e7a232012-04-15 00:35:50 +020069}
70
Laurent Vivier4d558f52011-09-17 21:21:07 +020071static void m68k_cpu_disas_set_info(CPUState *s, disassemble_info *info)
Peter Crosthwaite4f669902015-07-11 19:00:00 -070072{
Laurent Vivier4d558f52011-09-17 21:21:07 +020073 M68kCPU *cpu = M68K_CPU(s);
74 CPUM68KState *env = &cpu->env;
Peter Crosthwaite4f669902015-07-11 19:00:00 -070075 info->print_insn = print_insn_m68k;
Laurent Vivier4d558f52011-09-17 21:21:07 +020076 if (m68k_feature(env, M68K_FEATURE_M68000)) {
77 info->mach = bfd_mach_m68040;
78 }
Peter Crosthwaite4f669902015-07-11 19:00:00 -070079}
80
Andreas Färber11150912012-04-15 03:30:10 +020081/* CPU models */
82
Andreas Färberbc5b2da2013-01-21 17:50:15 +010083static ObjectClass *m68k_cpu_class_by_name(const char *cpu_model)
84{
85 ObjectClass *oc;
Andreas Färber7a9f8122013-01-27 20:16:17 +010086 char *typename;
Andreas Färberbc5b2da2013-01-21 17:50:15 +010087
Igor Mammedovf61797b2017-10-05 15:50:45 +020088 typename = g_strdup_printf(M68K_CPU_TYPE_NAME("%s"), cpu_model);
Andreas Färber7a9f8122013-01-27 20:16:17 +010089 oc = object_class_by_name(typename);
90 g_free(typename);
Andreas Färbercae85062013-01-23 12:36:31 +010091 if (oc != NULL && (object_class_dynamic_cast(oc, TYPE_M68K_CPU) == NULL ||
92 object_class_is_abstract(oc))) {
Andreas Färberbc5b2da2013-01-21 17:50:15 +010093 return NULL;
94 }
95 return oc;
96}
97
Andreas Färber11150912012-04-15 03:30:10 +020098static void m5206_cpu_initfn(Object *obj)
99{
100 M68kCPU *cpu = M68K_CPU(obj);
101 CPUM68KState *env = &cpu->env;
102
103 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
104}
105
Laurent Vivierf0768032015-06-23 20:55:08 +0200106static void m68000_cpu_initfn(Object *obj)
107{
108 M68kCPU *cpu = M68K_CPU(obj);
109 CPUM68KState *env = &cpu->env;
110
111 m68k_set_feature(env, M68K_FEATURE_M68000);
112 m68k_set_feature(env, M68K_FEATURE_USP);
113 m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
Pavel Dovgalyuk1226e212018-02-06 15:44:31 +0300114 m68k_set_feature(env, M68K_FEATURE_MOVEP);
Laurent Vivierf0768032015-06-23 20:55:08 +0200115}
116
Laurent Vivier18b61022019-12-20 18:24:15 +0100117/* common features for 68020, 68030 and 68040 */
118static void m680x0_cpu_common(CPUM68KState *env)
Laurent Vivierf0768032015-06-23 20:55:08 +0200119{
Laurent Vivierf0768032015-06-23 20:55:08 +0200120 m68k_set_feature(env, M68K_FEATURE_M68000);
121 m68k_set_feature(env, M68K_FEATURE_USP);
122 m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
123 m68k_set_feature(env, M68K_FEATURE_QUAD_MULDIV);
124 m68k_set_feature(env, M68K_FEATURE_BRAL);
125 m68k_set_feature(env, M68K_FEATURE_BCCL);
126 m68k_set_feature(env, M68K_FEATURE_BITFIELD);
127 m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
128 m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
129 m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV);
130 m68k_set_feature(env, M68K_FEATURE_FPU);
131 m68k_set_feature(env, M68K_FEATURE_CAS);
132 m68k_set_feature(env, M68K_FEATURE_BKPT);
Laurent Vivier18059c92017-06-05 12:00:14 +0200133 m68k_set_feature(env, M68K_FEATURE_RTD);
Laurent Vivier8bf6cba2018-01-04 02:29:03 +0100134 m68k_set_feature(env, M68K_FEATURE_CHK2);
Pavel Dovgalyuk1226e212018-02-06 15:44:31 +0300135 m68k_set_feature(env, M68K_FEATURE_MOVEP);
Laurent Vivierf0768032015-06-23 20:55:08 +0200136}
Laurent Vivier18b61022019-12-20 18:24:15 +0100137
138static void m68020_cpu_initfn(Object *obj)
139{
140 M68kCPU *cpu = M68K_CPU(obj);
141 CPUM68KState *env = &cpu->env;
142
143 m680x0_cpu_common(env);
144 m68k_set_feature(env, M68K_FEATURE_M68020);
145}
146
147static void m68030_cpu_initfn(Object *obj)
148{
149 M68kCPU *cpu = M68K_CPU(obj);
150 CPUM68KState *env = &cpu->env;
151
152 m680x0_cpu_common(env);
153 m68k_set_feature(env, M68K_FEATURE_M68030);
154}
Laurent Vivier9d4f0422018-01-04 02:29:04 +0100155
156static void m68040_cpu_initfn(Object *obj)
157{
158 M68kCPU *cpu = M68K_CPU(obj);
159 CPUM68KState *env = &cpu->env;
160
Laurent Vivier18b61022019-12-20 18:24:15 +0100161 m680x0_cpu_common(env);
Laurent Vivier9d4f0422018-01-04 02:29:04 +0100162 m68k_set_feature(env, M68K_FEATURE_M68040);
163}
Laurent Vivierf0768032015-06-23 20:55:08 +0200164
165static void m68060_cpu_initfn(Object *obj)
166{
167 M68kCPU *cpu = M68K_CPU(obj);
168 CPUM68KState *env = &cpu->env;
169
170 m68k_set_feature(env, M68K_FEATURE_M68000);
171 m68k_set_feature(env, M68K_FEATURE_USP);
172 m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
173 m68k_set_feature(env, M68K_FEATURE_BRAL);
174 m68k_set_feature(env, M68K_FEATURE_BCCL);
175 m68k_set_feature(env, M68K_FEATURE_BITFIELD);
176 m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
177 m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
178 m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV);
179 m68k_set_feature(env, M68K_FEATURE_FPU);
180 m68k_set_feature(env, M68K_FEATURE_CAS);
181 m68k_set_feature(env, M68K_FEATURE_BKPT);
Laurent Vivier18059c92017-06-05 12:00:14 +0200182 m68k_set_feature(env, M68K_FEATURE_RTD);
Laurent Vivier8bf6cba2018-01-04 02:29:03 +0100183 m68k_set_feature(env, M68K_FEATURE_CHK2);
Laurent Vivier18b61022019-12-20 18:24:15 +0100184 m68k_set_feature(env, M68K_FEATURE_M68060);
Laurent Vivierf0768032015-06-23 20:55:08 +0200185}
186
Andreas Färber11150912012-04-15 03:30:10 +0200187static void m5208_cpu_initfn(Object *obj)
188{
189 M68kCPU *cpu = M68K_CPU(obj);
190 CPUM68KState *env = &cpu->env;
191
192 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
193 m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
194 m68k_set_feature(env, M68K_FEATURE_BRAL);
195 m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
196 m68k_set_feature(env, M68K_FEATURE_USP);
197}
198
199static void cfv4e_cpu_initfn(Object *obj)
200{
201 M68kCPU *cpu = M68K_CPU(obj);
202 CPUM68KState *env = &cpu->env;
203
204 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
205 m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
206 m68k_set_feature(env, M68K_FEATURE_BRAL);
207 m68k_set_feature(env, M68K_FEATURE_CF_FPU);
208 m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
209 m68k_set_feature(env, M68K_FEATURE_USP);
210}
211
212static void any_cpu_initfn(Object *obj)
213{
214 M68kCPU *cpu = M68K_CPU(obj);
215 CPUM68KState *env = &cpu->env;
216
217 m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
218 m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
219 m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
220 m68k_set_feature(env, M68K_FEATURE_BRAL);
221 m68k_set_feature(env, M68K_FEATURE_CF_FPU);
Lucien Murray-Pitts808d77b2019-06-07 08:41:25 +0900222 /*
223 * MAC and EMAC are mututally exclusive, so pick EMAC.
224 * It's mostly backwards compatible.
225 */
Andreas Färber11150912012-04-15 03:30:10 +0200226 m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
227 m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
228 m68k_set_feature(env, M68K_FEATURE_USP);
229 m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
230 m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
231}
232
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100233static void m68k_cpu_realizefn(DeviceState *dev, Error **errp)
234{
Andreas Färber14a10fc2013-07-27 02:53:25 +0200235 CPUState *cs = CPU(dev);
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100236 M68kCPU *cpu = M68K_CPU(dev);
237 M68kCPUClass *mcc = M68K_CPU_GET_CLASS(dev);
Laurent Vivierce5b1bb2016-10-20 13:26:03 +0200238 Error *local_err = NULL;
239
Igor Mammedovf47cf4e2017-08-24 18:31:34 +0200240 register_m68k_insns(&cpu->env);
241
Laurent Vivierce5b1bb2016-10-20 13:26:03 +0200242 cpu_exec_realizefn(cs, &local_err);
243 if (local_err != NULL) {
244 error_propagate(errp, local_err);
245 return;
246 }
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100247
248 m68k_cpu_init_gdb(cpu);
249
Andreas Färber14a10fc2013-07-27 02:53:25 +0200250 cpu_reset(cs);
251 qemu_init_vcpu(cs);
Andreas Färber6d1bbc62013-01-05 15:15:30 +0100252
253 mcc->parent_realize(dev, errp);
254}
255
Andreas Färber9b706032012-04-15 01:10:56 +0200256static void m68k_cpu_initfn(Object *obj)
257{
258 M68kCPU *cpu = M68K_CPU(obj);
Andreas Färber9b706032012-04-15 01:10:56 +0200259
Richard Henderson7506ed92019-03-28 11:26:22 -1000260 cpu_set_cpustate_pointers(cpu);
Andreas Färber9b706032012-04-15 01:10:56 +0200261}
262
Andreas Färber087fe4f2013-01-20 19:53:28 +0100263static const VMStateDescription vmstate_m68k_cpu = {
264 .name = "cpu",
265 .unmigratable = 1,
266};
267
Andreas Färberb9e7a232012-04-15 00:35:50 +0200268static void m68k_cpu_class_init(ObjectClass *c, void *data)
269{
270 M68kCPUClass *mcc = M68K_CPU_CLASS(c);
271 CPUClass *cc = CPU_CLASS(c);
Andreas Färber087fe4f2013-01-20 19:53:28 +0100272 DeviceClass *dc = DEVICE_CLASS(c);
Andreas Färberb9e7a232012-04-15 00:35:50 +0200273
Philippe Mathieu-Daudébf853882018-01-13 23:04:12 -0300274 device_class_set_parent_realize(dc, m68k_cpu_realizefn,
275 &mcc->parent_realize);
Peter Maydell781c67c2020-03-03 10:05:11 +0000276 device_class_set_parent_reset(dc, m68k_cpu_reset, &mcc->parent_reset);
Andreas Färberbc5b2da2013-01-21 17:50:15 +0100277
278 cc->class_by_name = m68k_cpu_class_by_name;
Andreas Färber8c2e1b02013-08-25 18:53:55 +0200279 cc->has_work = m68k_cpu_has_work;
Andreas Färber97a8ea52013-02-02 10:57:51 +0100280 cc->do_interrupt = m68k_cpu_do_interrupt;
Richard Hendersonab409bb2014-09-13 09:45:20 -0700281 cc->cpu_exec_interrupt = m68k_cpu_exec_interrupt;
Andreas Färber878096e2013-05-27 01:33:50 +0200282 cc->dump_state = m68k_cpu_dump_state;
Andreas Färbere7006042013-06-28 20:35:01 +0200283 cc->set_pc = m68k_cpu_set_pc;
Andreas Färber5b50e792013-06-29 04:18:45 +0200284 cc->gdb_read_register = m68k_cpu_gdb_read_register;
285 cc->gdb_write_register = m68k_cpu_gdb_write_register;
Richard Hendersonfe5f7b12019-04-02 15:55:10 +0700286 cc->tlb_fill = m68k_cpu_tlb_fill;
Laurent Vivier88b2fef2018-01-18 20:38:41 +0100287#if defined(CONFIG_SOFTMMU)
Peter Maydelle1aaf3a2018-12-10 16:56:36 +0000288 cc->do_transaction_failed = m68k_cpu_transaction_failed;
Andreas Färber00b941e2013-06-29 18:55:54 +0200289 cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
290#endif
Peter Crosthwaite4f669902015-07-11 19:00:00 -0700291 cc->disas_set_info = m68k_cpu_disas_set_info;
Richard Henderson55c3cee2017-10-15 19:02:42 -0700292 cc->tcg_initialize = m68k_tcg_init;
Richard Henderson00f3fd62014-09-13 09:45:15 -0700293
Andreas Färbera0e372f2013-06-28 23:18:47 +0200294 cc->gdb_num_core_regs = 18;
Markus Armbruster4c315c22015-10-01 10:59:58 +0200295
Peter Crosthwaite4f669902015-07-11 19:00:00 -0700296 dc->vmsd = &vmstate_m68k_cpu;
Andreas Färberb9e7a232012-04-15 00:35:50 +0200297}
298
KONRAD Frederica976ed32020-04-30 20:01:22 +0100299static void m68k_cpu_class_init_cf_core(ObjectClass *c, void *data)
300{
301 CPUClass *cc = CPU_CLASS(c);
302
303 cc->gdb_core_xml_file = "cf-core.xml";
304}
305
306#define DEFINE_M68K_CPU_TYPE_CF(model) \
307 { \
308 .name = M68K_CPU_TYPE_NAME(#model), \
309 .instance_init = model##_cpu_initfn, \
310 .parent = TYPE_M68K_CPU, \
311 .class_init = m68k_cpu_class_init_cf_core \
312 }
313
314static void m68k_cpu_class_init_m68k_core(ObjectClass *c, void *data)
315{
316 CPUClass *cc = CPU_CLASS(c);
317
318 cc->gdb_core_xml_file = "m68k-core.xml";
319}
320
321#define DEFINE_M68K_CPU_TYPE_M68K(model) \
322 { \
323 .name = M68K_CPU_TYPE_NAME(#model), \
324 .instance_init = model##_cpu_initfn, \
325 .parent = TYPE_M68K_CPU, \
326 .class_init = m68k_cpu_class_init_m68k_core \
Igor Mammedovf61797b2017-10-05 15:50:45 +0200327 }
Andreas Färber11150912012-04-15 03:30:10 +0200328
Igor Mammedovf61797b2017-10-05 15:50:45 +0200329static const TypeInfo m68k_cpus_type_infos[] = {
330 { /* base class should be registered first */
331 .name = TYPE_M68K_CPU,
332 .parent = TYPE_CPU,
333 .instance_size = sizeof(M68kCPU),
334 .instance_init = m68k_cpu_initfn,
335 .abstract = true,
336 .class_size = sizeof(M68kCPUClass),
337 .class_init = m68k_cpu_class_init,
338 },
KONRAD Frederica976ed32020-04-30 20:01:22 +0100339 DEFINE_M68K_CPU_TYPE_M68K(m68000),
340 DEFINE_M68K_CPU_TYPE_M68K(m68020),
341 DEFINE_M68K_CPU_TYPE_M68K(m68030),
342 DEFINE_M68K_CPU_TYPE_M68K(m68040),
343 DEFINE_M68K_CPU_TYPE_M68K(m68060),
344 DEFINE_M68K_CPU_TYPE_CF(m5206),
345 DEFINE_M68K_CPU_TYPE_CF(m5208),
346 DEFINE_M68K_CPU_TYPE_CF(cfv4e),
347 DEFINE_M68K_CPU_TYPE_CF(any),
Andreas Färberb9e7a232012-04-15 00:35:50 +0200348};
349
Igor Mammedovf61797b2017-10-05 15:50:45 +0200350DEFINE_TYPES(m68k_cpus_type_infos)