master
c 379 lines 11.2 KB
Raw
1 /*
2 * QEMU SuperH CPU
3 *
4 * Copyright (c) 2005 Samuel Tardieu
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 "migration/vmstate.h"
27 #include "exec/translation-block.h"
28 #include "fpu/softfloat-helpers.h"
29 #include "accel/tcg/cpu-ops.h"
30 #include "tcg/tcg.h"
31 #include "disas/capstone.h"
32
33 static void superh_cpu_set_pc(CPUState *cs, vaddr value)
34 {
35 SuperHCPU *cpu = SUPERH_CPU(cs);
36
37 cpu->env.pc = value;
38 }
39
40 static vaddr superh_cpu_get_pc(CPUState *cs)
41 {
42 SuperHCPU *cpu = SUPERH_CPU(cs);
43
44 return cpu->env.pc;
45 }
46
47 static TCGTBCPUState superh_get_tb_cpu_state(CPUState *cs)
48 {
49 CPUSH4State *env = cpu_env(cs);
50 uint32_t flags;
51
52 flags = env->flags
53 | (env->fpscr & TB_FLAG_FPSCR_MASK)
54 | (env->sr & TB_FLAG_SR_MASK)
55 | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */
56 #ifdef CONFIG_USER_ONLY
57 flags |= TB_FLAG_UNALIGN * !cs->prctl_unalign_sigbus;
58 #endif
59
60 return (TCGTBCPUState){
61 .pc = env->pc,
62 .flags = flags,
63 #ifdef CONFIG_USER_ONLY
64 /* For a gUSA region, notice the end of the region. */
65 .cs_base = flags & TB_FLAG_GUSA_MASK ? env->gregs[0] : 0,
66 #endif
67 };
68 }
69
70 static void superh_cpu_synchronize_from_tb(CPUState *cs,
71 const TranslationBlock *tb)
72 {
73 SuperHCPU *cpu = SUPERH_CPU(cs);
74
75 tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL));
76 cpu->env.pc = tb->pc;
77 cpu->env.flags = tb->flags & TB_FLAG_ENVFLAGS_MASK;
78 }
79
80 static void superh_restore_state_to_opc(CPUState *cs,
81 const TranslationBlock *tb,
82 const uint64_t *data)
83 {
84 SuperHCPU *cpu = SUPERH_CPU(cs);
85
86 cpu->env.pc = data[0];
87 cpu->env.flags = data[1];
88 /*
89 * Theoretically delayed_pc should also be restored. In practice the
90 * branch instruction is re-executed after exception, so the delayed
91 * branch target will be recomputed.
92 */
93 }
94
95 #ifndef CONFIG_USER_ONLY
96 static bool superh_io_recompile_replay_branch(CPUState *cs,
97 const TranslationBlock *tb)
98 {
99 CPUSH4State *env = cpu_env(cs);
100
101 if ((env->flags & (TB_FLAG_DELAY_SLOT | TB_FLAG_DELAY_SLOT_COND))
102 && !tcg_cflags_has(cs, CF_PCREL) && env->pc != tb->pc) {
103 env->pc -= 2;
104 env->flags &= ~(TB_FLAG_DELAY_SLOT | TB_FLAG_DELAY_SLOT_COND);
105 return true;
106 }
107 return false;
108 }
109
110 static bool superh_cpu_has_work(CPUState *cs)
111 {
112 return cpu_test_interrupt(cs, CPU_INTERRUPT_HARD);
113 }
114 #endif /* !CONFIG_USER_ONLY */
115
116 static int sh4_cpu_mmu_index(CPUState *cs, bool ifetch)
117 {
118 CPUSH4State *env = cpu_env(cs);
119
120 /*
121 * The instruction in a RTE delay slot is fetched in privileged mode,
122 * but executed in user mode.
123 */
124 if (ifetch && (env->flags & TB_FLAG_DELAY_SLOT_RTE)) {
125 return 0;
126 } else {
127 return (env->sr & (1u << SR_MD)) == 0 ? 1 : 0;
128 }
129 }
130
131 static void superh_cpu_reset_hold(Object *obj, ResetType type)
132 {
133 CPUState *cs = CPU(obj);
134 SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(obj);
135 CPUSH4State *env = cpu_env(cs);
136
137 if (scc->parent_phases.hold) {
138 scc->parent_phases.hold(obj, type);
139 }
140
141 memset(env, 0, offsetof(CPUSH4State, end_reset_fields));
142
143 env->pc = 0xA0000000;
144 #if defined(CONFIG_USER_ONLY)
145 env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
146 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */
147 #else
148 env->sr = (1u << SR_MD) | (1u << SR_RB) | (1u << SR_BL) |
149 (1u << SR_I3) | (1u << SR_I2) | (1u << SR_I1) | (1u << SR_I0);
150 env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */
151 set_float_rounding_mode(float_round_to_zero, &env->fp_status);
152 set_flush_to_zero(1, &env->fp_status);
153 #endif
154 set_default_nan_mode(1, &env->fp_status);
155 set_snan_rule(float_snan_bit_is_one, &env->fp_status);
156 /* sign bit clear, set all frac bits other than msb */
157 set_float_default_nan_pattern(0b00111111, &env->fp_status);
158 /*
159 * TODO: "SH-4 CPU Core Architecture ADCS 7182230F" doesn't say whether
160 * it detects tininess before or after rounding. Section 6.4 is clear
161 * that flush-to-zero happens when the result underflows, though, so
162 * either this should be "detect ftz after rounding" or else we should
163 * be setting "detect tininess before rounding".
164 */
165 set_float_ftz_detection(float_ftz_before_rounding, &env->fp_status);
166 }
167
168 static void superh_cpu_disas_set_info(const CPUState *cpu,
169 disassemble_info *info)
170 {
171 const CPUSH4State *env = cpu_env((CPUState *)cpu);
172
173 info->endian = TARGET_BIG_ENDIAN ? BFD_ENDIAN_BIG
174 : BFD_ENDIAN_LITTLE;
175 info->mach = bfd_mach_sh4;
176 info->print_insn = print_insn_sh;
177
178 info->cap_arch = CS_ARCH_SH;
179 info->cap_insn_unit = 2;
180 info->cap_insn_split = 2;
181 /*
182 * Possible capstone bug: the isa levels are not additive:
183 * least significant bit wins, so SH4 overrides SH4A.
184 * Work around by setting one or the other but not both.
185 */
186 info->cap_mode = CS_MODE_SHFPU
187 | (env->features & SH_FEATURE_SH4A ? CS_MODE_SH4A : CS_MODE_SH4);
188 }
189
190 static ObjectClass *superh_cpu_class_by_name(const char *cpu_model)
191 {
192 ObjectClass *oc;
193 char *s, *typename = NULL;
194
195 s = g_ascii_strdown(cpu_model, -1);
196 if (strcmp(s, "any") == 0) {
197 oc = object_class_by_name(TYPE_SH7750R_CPU);
198 goto out;
199 }
200
201 typename = g_strdup_printf(SUPERH_CPU_TYPE_NAME("%s"), s);
202 oc = object_class_by_name(typename);
203
204 out:
205 g_free(s);
206 g_free(typename);
207 return oc;
208 }
209
210 static void sh7750r_cpu_initfn(Object *obj)
211 {
212 CPUSH4State *env = cpu_env(CPU(obj));
213
214 env->id = SH_CPU_SH7750R;
215 env->features = SH_FEATURE_BCR3_AND_BCR4;
216 }
217
218 static void sh7750r_class_init(ObjectClass *oc, const void *data)
219 {
220 SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
221
222 scc->pvr = 0x00050000;
223 scc->prr = 0x00000100;
224 scc->cvr = 0x00110000;
225 }
226
227 static void sh7751r_cpu_initfn(Object *obj)
228 {
229 CPUSH4State *env = cpu_env(CPU(obj));
230
231 env->id = SH_CPU_SH7751R;
232 env->features = SH_FEATURE_BCR3_AND_BCR4;
233 }
234
235 static void sh7751r_class_init(ObjectClass *oc, const void *data)
236 {
237 SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
238
239 scc->pvr = 0x04050005;
240 scc->prr = 0x00000113;
241 scc->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */
242 }
243
244 static void sh7785_cpu_initfn(Object *obj)
245 {
246 CPUSH4State *env = cpu_env(CPU(obj));
247
248 env->id = SH_CPU_SH7785;
249 env->features = SH_FEATURE_SH4A;
250 }
251
252 static void sh7785_class_init(ObjectClass *oc, const void *data)
253 {
254 SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
255
256 scc->pvr = 0x10300700;
257 scc->prr = 0x00000200;
258 scc->cvr = 0x71440211;
259 }
260
261 static void superh_cpu_realizefn(DeviceState *dev, Error **errp)
262 {
263 CPUState *cs = CPU(dev);
264 SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev);
265 Error *local_err = NULL;
266
267 cpu_common_realize(cs, &local_err);
268 if (local_err != NULL) {
269 error_propagate(errp, local_err);
270 return;
271 }
272
273 qemu_init_vcpu(cs);
274
275 scc->parent_realize(dev, errp);
276 }
277
278 static void superh_cpu_initfn(Object *obj)
279 {
280 CPUSH4State *env = cpu_env(CPU(obj));
281
282 env->movcal_backup_tail = &(env->movcal_backup);
283 }
284
285 #ifndef CONFIG_USER_ONLY
286 static const VMStateDescription vmstate_sh_cpu = {
287 .name = "cpu",
288 .unmigratable = 1,
289 };
290
291 #include "hw/core/sysemu-cpu-ops.h"
292
293 static const struct SysemuCPUOps sh4_sysemu_ops = {
294 .has_work = superh_cpu_has_work,
295 .get_phys_addr_debug = superh_cpu_get_phys_addr_debug,
296 };
297 #endif
298
299 static const TCGCPUOps superh_tcg_ops = {
300 /* MTTCG not yet supported: require strict ordering */
301 .guest_default_memory_order = TCG_MO_ALL,
302 .mttcg_supported = false,
303
304 .initialize = sh4_translate_init,
305 .translate_code = sh4_translate_code,
306 .get_tb_cpu_state = superh_get_tb_cpu_state,
307 .synchronize_from_tb = superh_cpu_synchronize_from_tb,
308 .restore_state_to_opc = superh_restore_state_to_opc,
309 .mmu_index = sh4_cpu_mmu_index,
310
311 #ifndef CONFIG_USER_ONLY
312 .tlb_fill = superh_cpu_tlb_fill,
313 .pointer_wrap = cpu_pointer_wrap_notreached,
314 .cpu_exec_interrupt = superh_cpu_exec_interrupt,
315 .cpu_exec_halt = superh_cpu_has_work,
316 .cpu_exec_reset = cpu_reset,
317 .do_interrupt = superh_cpu_do_interrupt,
318 .do_unaligned_access = superh_cpu_do_unaligned_access,
319 .io_recompile_replay_branch = superh_io_recompile_replay_branch,
320 #endif /* !CONFIG_USER_ONLY */
321 };
322
323 static void superh_cpu_class_init(ObjectClass *oc, const void *data)
324 {
325 DeviceClass *dc = DEVICE_CLASS(oc);
326 CPUClass *cc = CPU_CLASS(oc);
327 SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
328 ResettableClass *rc = RESETTABLE_CLASS(oc);
329
330 device_class_set_parent_realize(dc, superh_cpu_realizefn,
331 &scc->parent_realize);
332
333 resettable_class_set_parent_phases(rc, NULL, superh_cpu_reset_hold, NULL,
334 &scc->parent_phases);
335
336 cc->class_by_name = superh_cpu_class_by_name;
337 cc->dump_state = superh_cpu_dump_state;
338 cc->set_pc = superh_cpu_set_pc;
339 cc->get_pc = superh_cpu_get_pc;
340 cc->gdb_read_register = superh_cpu_gdb_read_register;
341 cc->gdb_write_register = superh_cpu_gdb_write_register;
342 #ifndef CONFIG_USER_ONLY
343 cc->sysemu_ops = &sh4_sysemu_ops;
344 dc->vmsd = &vmstate_sh_cpu;
345 #endif
346 cc->disas_set_info = superh_cpu_disas_set_info;
347
348 cc->gdb_num_core_regs = 59;
349 cc->tcg_ops = &superh_tcg_ops;
350 }
351
352 #define DEFINE_SUPERH_CPU_TYPE(type_name, cinit, initfn) \
353 { \
354 .name = type_name, \
355 .parent = TYPE_SUPERH_CPU, \
356 .class_init = cinit, \
357 .instance_init = initfn, \
358 }
359 static const TypeInfo superh_cpu_type_infos[] = {
360 {
361 .name = TYPE_SUPERH_CPU,
362 .parent = TYPE_CPU,
363 .instance_size = sizeof(SuperHCPU),
364 .instance_align = __alignof(SuperHCPU),
365 .instance_init = superh_cpu_initfn,
366 .abstract = true,
367 .class_size = sizeof(SuperHCPUClass),
368 .class_init = superh_cpu_class_init,
369 },
370 DEFINE_SUPERH_CPU_TYPE(TYPE_SH7750R_CPU, sh7750r_class_init,
371 sh7750r_cpu_initfn),
372 DEFINE_SUPERH_CPU_TYPE(TYPE_SH7751R_CPU, sh7751r_class_init,
373 sh7751r_cpu_initfn),
374 DEFINE_SUPERH_CPU_TYPE(TYPE_SH7785_CPU, sh7785_class_init,
375 sh7785_cpu_initfn),
376
377 };
378
379 DEFINE_TYPES(superh_cpu_type_infos)