1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth * QEMU SuperH CPU
3fcf5ef2aSThomas Huth *
4fcf5ef2aSThomas Huth * Copyright (c) 2005 Samuel Tardieu
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 "migration/vmstate.h"
27fcf5ef2aSThomas Huth #include "exec/exec-all.h"
285f8ab000SAlex Bennée #include "fpu/softfloat-helpers.h"
29dd69c77cSAnton Johansson #include "tcg/tcg.h"
30fcf5ef2aSThomas Huth
superh_cpu_set_pc(CPUState * cs,vaddr value)31fcf5ef2aSThomas Huth static void superh_cpu_set_pc(CPUState *cs, vaddr value)
32fcf5ef2aSThomas Huth {
33fcf5ef2aSThomas Huth SuperHCPU *cpu = SUPERH_CPU(cs);
34fcf5ef2aSThomas Huth
35fcf5ef2aSThomas Huth cpu->env.pc = value;
36fcf5ef2aSThomas Huth }
37fcf5ef2aSThomas Huth
superh_cpu_get_pc(CPUState * cs)38e4fdf9dfSRichard Henderson static vaddr superh_cpu_get_pc(CPUState *cs)
39e4fdf9dfSRichard Henderson {
40e4fdf9dfSRichard Henderson SuperHCPU *cpu = SUPERH_CPU(cs);
41e4fdf9dfSRichard Henderson
42e4fdf9dfSRichard Henderson return cpu->env.pc;
43e4fdf9dfSRichard Henderson }
44e4fdf9dfSRichard Henderson
superh_cpu_synchronize_from_tb(CPUState * cs,const TranslationBlock * tb)4504a37d4cSRichard Henderson static void superh_cpu_synchronize_from_tb(CPUState *cs,
4604a37d4cSRichard Henderson const TranslationBlock *tb)
47fcf5ef2aSThomas Huth {
48fcf5ef2aSThomas Huth SuperHCPU *cpu = SUPERH_CPU(cs);
49fcf5ef2aSThomas Huth
50b254c342SPhilippe Mathieu-Daudé tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL));
51dd69c77cSAnton Johansson cpu->env.pc = tb->pc;
52bc233163SGuenter Roeck cpu->env.flags = tb->flags & TB_FLAG_ENVFLAGS_MASK;
53fcf5ef2aSThomas Huth }
54fcf5ef2aSThomas Huth
superh_restore_state_to_opc(CPUState * cs,const TranslationBlock * tb,const uint64_t * data)55e7977326SRichard Henderson static void superh_restore_state_to_opc(CPUState *cs,
56e7977326SRichard Henderson const TranslationBlock *tb,
57e7977326SRichard Henderson const uint64_t *data)
58e7977326SRichard Henderson {
59e7977326SRichard Henderson SuperHCPU *cpu = SUPERH_CPU(cs);
60e7977326SRichard Henderson
61e7977326SRichard Henderson cpu->env.pc = data[0];
62e7977326SRichard Henderson cpu->env.flags = data[1];
63e7977326SRichard Henderson /*
64e7977326SRichard Henderson * Theoretically delayed_pc should also be restored. In practice the
65e7977326SRichard Henderson * branch instruction is re-executed after exception, so the delayed
66e7977326SRichard Henderson * branch target will be recomputed.
67e7977326SRichard Henderson */
68e7977326SRichard Henderson }
69e7977326SRichard Henderson
70eb56afdbSRichard Henderson #ifndef CONFIG_USER_ONLY
superh_io_recompile_replay_branch(CPUState * cs,const TranslationBlock * tb)71eb56afdbSRichard Henderson static bool superh_io_recompile_replay_branch(CPUState *cs,
72eb56afdbSRichard Henderson const TranslationBlock *tb)
73eb56afdbSRichard Henderson {
74795bec96SPhilippe Mathieu-Daudé CPUSH4State *env = cpu_env(cs);
75eb56afdbSRichard Henderson
76ab419fd8SRichard Henderson if ((env->flags & (TB_FLAG_DELAY_SLOT | TB_FLAG_DELAY_SLOT_COND))
77b254c342SPhilippe Mathieu-Daudé && !tcg_cflags_has(cs, CF_PCREL) && env->pc != tb->pc) {
78eb56afdbSRichard Henderson env->pc -= 2;
79ab419fd8SRichard Henderson env->flags &= ~(TB_FLAG_DELAY_SLOT | TB_FLAG_DELAY_SLOT_COND);
80eb56afdbSRichard Henderson return true;
81eb56afdbSRichard Henderson }
82eb56afdbSRichard Henderson return false;
83eb56afdbSRichard Henderson }
84eb56afdbSRichard Henderson #endif
85eb56afdbSRichard Henderson
superh_cpu_has_work(CPUState * cs)86fcf5ef2aSThomas Huth static bool superh_cpu_has_work(CPUState *cs)
87fcf5ef2aSThomas Huth {
88fcf5ef2aSThomas Huth return cs->interrupt_request & CPU_INTERRUPT_HARD;
89fcf5ef2aSThomas Huth }
90fcf5ef2aSThomas Huth
sh4_cpu_mmu_index(CPUState * cs,bool ifetch)91a120d320SRichard Henderson static int sh4_cpu_mmu_index(CPUState *cs, bool ifetch)
929ba49d72SRichard Henderson {
939ba49d72SRichard Henderson CPUSH4State *env = cpu_env(cs);
949ba49d72SRichard Henderson
959ba49d72SRichard Henderson /*
969ba49d72SRichard Henderson * The instruction in a RTE delay slot is fetched in privileged mode,
979ba49d72SRichard Henderson * but executed in user mode.
989ba49d72SRichard Henderson */
999ba49d72SRichard Henderson if (ifetch && (env->flags & TB_FLAG_DELAY_SLOT_RTE)) {
1009ba49d72SRichard Henderson return 0;
1019ba49d72SRichard Henderson } else {
1029ba49d72SRichard Henderson return (env->sr & (1u << SR_MD)) == 0 ? 1 : 0;
1039ba49d72SRichard Henderson }
1049ba49d72SRichard Henderson }
1059ba49d72SRichard Henderson
superh_cpu_reset_hold(Object * obj,ResetType type)106ad80e367SPeter Maydell static void superh_cpu_reset_hold(Object *obj, ResetType type)
107fcf5ef2aSThomas Huth {
108348802b5SPhilippe Mathieu-Daudé CPUState *cs = CPU(obj);
109348802b5SPhilippe Mathieu-Daudé SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(obj);
110795bec96SPhilippe Mathieu-Daudé CPUSH4State *env = cpu_env(cs);
111fcf5ef2aSThomas Huth
11290493830SPeter Maydell if (scc->parent_phases.hold) {
113ad80e367SPeter Maydell scc->parent_phases.hold(obj, type);
11490493830SPeter Maydell }
115fcf5ef2aSThomas Huth
1161f5c00cfSAlex Bennée memset(env, 0, offsetof(CPUSH4State, end_reset_fields));
117fcf5ef2aSThomas Huth
118fcf5ef2aSThomas Huth env->pc = 0xA0000000;
119fcf5ef2aSThomas Huth #if defined(CONFIG_USER_ONLY)
120fcf5ef2aSThomas Huth env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
121fcf5ef2aSThomas Huth set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */
122fcf5ef2aSThomas Huth #else
123fcf5ef2aSThomas Huth env->sr = (1u << SR_MD) | (1u << SR_RB) | (1u << SR_BL) |
124fcf5ef2aSThomas Huth (1u << SR_I3) | (1u << SR_I2) | (1u << SR_I1) | (1u << SR_I0);
125fcf5ef2aSThomas Huth env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */
126fcf5ef2aSThomas Huth set_float_rounding_mode(float_round_to_zero, &env->fp_status);
127fcf5ef2aSThomas Huth set_flush_to_zero(1, &env->fp_status);
128fcf5ef2aSThomas Huth #endif
129fcf5ef2aSThomas Huth set_default_nan_mode(1, &env->fp_status);
130fcf5ef2aSThomas Huth }
131fcf5ef2aSThomas Huth
superh_cpu_disas_set_info(CPUState * cpu,disassemble_info * info)132fcf5ef2aSThomas Huth static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
133fcf5ef2aSThomas Huth {
134fcf5ef2aSThomas Huth info->mach = bfd_mach_sh4;
135fcf5ef2aSThomas Huth info->print_insn = print_insn_sh;
136fcf5ef2aSThomas Huth }
137fcf5ef2aSThomas Huth
superh_cpu_class_by_name(const char * cpu_model)138fcf5ef2aSThomas Huth static ObjectClass *superh_cpu_class_by_name(const char *cpu_model)
139fcf5ef2aSThomas Huth {
140fcf5ef2aSThomas Huth ObjectClass *oc;
141d5ebe625SIgor Mammedov char *s, *typename = NULL;
142fcf5ef2aSThomas Huth
143d5ebe625SIgor Mammedov s = g_ascii_strdown(cpu_model, -1);
144d5ebe625SIgor Mammedov if (strcmp(s, "any") == 0) {
145d5ebe625SIgor Mammedov oc = object_class_by_name(TYPE_SH7750R_CPU);
146d5ebe625SIgor Mammedov goto out;
147fcf5ef2aSThomas Huth }
148fcf5ef2aSThomas Huth
149d5ebe625SIgor Mammedov typename = g_strdup_printf(SUPERH_CPU_TYPE_NAME("%s"), s);
150d5ebe625SIgor Mammedov oc = object_class_by_name(typename);
151d5ebe625SIgor Mammedov
152d5ebe625SIgor Mammedov out:
153d5ebe625SIgor Mammedov g_free(s);
154d5ebe625SIgor Mammedov g_free(typename);
155fcf5ef2aSThomas Huth return oc;
156fcf5ef2aSThomas Huth }
157fcf5ef2aSThomas Huth
sh7750r_cpu_initfn(Object * obj)158fcf5ef2aSThomas Huth static void sh7750r_cpu_initfn(Object *obj)
159fcf5ef2aSThomas Huth {
160795bec96SPhilippe Mathieu-Daudé CPUSH4State *env = cpu_env(CPU(obj));
161fcf5ef2aSThomas Huth
162fcf5ef2aSThomas Huth env->id = SH_CPU_SH7750R;
163fcf5ef2aSThomas Huth env->features = SH_FEATURE_BCR3_AND_BCR4;
164fcf5ef2aSThomas Huth }
165fcf5ef2aSThomas Huth
sh7750r_class_init(ObjectClass * oc,void * data)166fcf5ef2aSThomas Huth static void sh7750r_class_init(ObjectClass *oc, void *data)
167fcf5ef2aSThomas Huth {
168fcf5ef2aSThomas Huth SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
169fcf5ef2aSThomas Huth
170fcf5ef2aSThomas Huth scc->pvr = 0x00050000;
171fcf5ef2aSThomas Huth scc->prr = 0x00000100;
172fcf5ef2aSThomas Huth scc->cvr = 0x00110000;
173fcf5ef2aSThomas Huth }
174fcf5ef2aSThomas Huth
sh7751r_cpu_initfn(Object * obj)175fcf5ef2aSThomas Huth static void sh7751r_cpu_initfn(Object *obj)
176fcf5ef2aSThomas Huth {
177795bec96SPhilippe Mathieu-Daudé CPUSH4State *env = cpu_env(CPU(obj));
178fcf5ef2aSThomas Huth
179fcf5ef2aSThomas Huth env->id = SH_CPU_SH7751R;
180fcf5ef2aSThomas Huth env->features = SH_FEATURE_BCR3_AND_BCR4;
181fcf5ef2aSThomas Huth }
182fcf5ef2aSThomas Huth
sh7751r_class_init(ObjectClass * oc,void * data)183fcf5ef2aSThomas Huth static void sh7751r_class_init(ObjectClass *oc, void *data)
184fcf5ef2aSThomas Huth {
185fcf5ef2aSThomas Huth SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
186fcf5ef2aSThomas Huth
187fcf5ef2aSThomas Huth scc->pvr = 0x04050005;
188fcf5ef2aSThomas Huth scc->prr = 0x00000113;
189fcf5ef2aSThomas Huth scc->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */
190fcf5ef2aSThomas Huth }
191fcf5ef2aSThomas Huth
sh7785_cpu_initfn(Object * obj)192fcf5ef2aSThomas Huth static void sh7785_cpu_initfn(Object *obj)
193fcf5ef2aSThomas Huth {
194795bec96SPhilippe Mathieu-Daudé CPUSH4State *env = cpu_env(CPU(obj));
195fcf5ef2aSThomas Huth
196fcf5ef2aSThomas Huth env->id = SH_CPU_SH7785;
197fcf5ef2aSThomas Huth env->features = SH_FEATURE_SH4A;
198fcf5ef2aSThomas Huth }
199fcf5ef2aSThomas Huth
sh7785_class_init(ObjectClass * oc,void * data)200fcf5ef2aSThomas Huth static void sh7785_class_init(ObjectClass *oc, void *data)
201fcf5ef2aSThomas Huth {
202fcf5ef2aSThomas Huth SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
203fcf5ef2aSThomas Huth
204fcf5ef2aSThomas Huth scc->pvr = 0x10300700;
205fcf5ef2aSThomas Huth scc->prr = 0x00000200;
206fcf5ef2aSThomas Huth scc->cvr = 0x71440211;
207fcf5ef2aSThomas Huth }
208fcf5ef2aSThomas Huth
superh_cpu_realizefn(DeviceState * dev,Error ** errp)209fcf5ef2aSThomas Huth static void superh_cpu_realizefn(DeviceState *dev, Error **errp)
210fcf5ef2aSThomas Huth {
211fcf5ef2aSThomas Huth CPUState *cs = CPU(dev);
212fcf5ef2aSThomas Huth SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev);
213fcf5ef2aSThomas Huth Error *local_err = NULL;
214fcf5ef2aSThomas Huth
215fcf5ef2aSThomas Huth cpu_exec_realizefn(cs, &local_err);
216fcf5ef2aSThomas Huth if (local_err != NULL) {
217fcf5ef2aSThomas Huth error_propagate(errp, local_err);
218fcf5ef2aSThomas Huth return;
219fcf5ef2aSThomas Huth }
220fcf5ef2aSThomas Huth
221fcf5ef2aSThomas Huth cpu_reset(cs);
222fcf5ef2aSThomas Huth qemu_init_vcpu(cs);
223fcf5ef2aSThomas Huth
224fcf5ef2aSThomas Huth scc->parent_realize(dev, errp);
225fcf5ef2aSThomas Huth }
226fcf5ef2aSThomas Huth
superh_cpu_initfn(Object * obj)227fcf5ef2aSThomas Huth static void superh_cpu_initfn(Object *obj)
228fcf5ef2aSThomas Huth {
229795bec96SPhilippe Mathieu-Daudé CPUSH4State *env = cpu_env(CPU(obj));
230fcf5ef2aSThomas Huth
231fcf5ef2aSThomas Huth env->movcal_backup_tail = &(env->movcal_backup);
232fcf5ef2aSThomas Huth }
233fcf5ef2aSThomas Huth
2344336073bSPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY
235fcf5ef2aSThomas Huth static const VMStateDescription vmstate_sh_cpu = {
236fcf5ef2aSThomas Huth .name = "cpu",
237fcf5ef2aSThomas Huth .unmigratable = 1,
238fcf5ef2aSThomas Huth };
2398b80bd28SPhilippe Mathieu-Daudé
2408b80bd28SPhilippe Mathieu-Daudé #include "hw/core/sysemu-cpu-ops.h"
2418b80bd28SPhilippe Mathieu-Daudé
2428b80bd28SPhilippe Mathieu-Daudé static const struct SysemuCPUOps sh4_sysemu_ops = {
24308928c6dSPhilippe Mathieu-Daudé .get_phys_page_debug = superh_cpu_get_phys_page_debug,
2448b80bd28SPhilippe Mathieu-Daudé };
2454336073bSPhilippe Mathieu-Daudé #endif
246fcf5ef2aSThomas Huth
24778271684SClaudio Fontana #include "hw/core/tcg-cpu-ops.h"
24878271684SClaudio Fontana
2491764ad70SRichard Henderson static const TCGCPUOps superh_tcg_ops = {
25078271684SClaudio Fontana .initialize = sh4_translate_init,
25178271684SClaudio Fontana .synchronize_from_tb = superh_cpu_synchronize_from_tb,
252e7977326SRichard Henderson .restore_state_to_opc = superh_restore_state_to_opc,
25378271684SClaudio Fontana
25478271684SClaudio Fontana #ifndef CONFIG_USER_ONLY
255cac720ecSRichard Henderson .tlb_fill = superh_cpu_tlb_fill,
25673166ca3SPhilippe Mathieu-Daudé .cpu_exec_interrupt = superh_cpu_exec_interrupt,
257*4f7b1ecbSPeter Maydell .cpu_exec_halt = superh_cpu_has_work,
25878271684SClaudio Fontana .do_interrupt = superh_cpu_do_interrupt,
25978271684SClaudio Fontana .do_unaligned_access = superh_cpu_do_unaligned_access,
260eb56afdbSRichard Henderson .io_recompile_replay_branch = superh_io_recompile_replay_branch,
26178271684SClaudio Fontana #endif /* !CONFIG_USER_ONLY */
26278271684SClaudio Fontana };
26378271684SClaudio Fontana
superh_cpu_class_init(ObjectClass * oc,void * data)264fcf5ef2aSThomas Huth static void superh_cpu_class_init(ObjectClass *oc, void *data)
265fcf5ef2aSThomas Huth {
266fcf5ef2aSThomas Huth DeviceClass *dc = DEVICE_CLASS(oc);
267fcf5ef2aSThomas Huth CPUClass *cc = CPU_CLASS(oc);
268fcf5ef2aSThomas Huth SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
26990493830SPeter Maydell ResettableClass *rc = RESETTABLE_CLASS(oc);
270fcf5ef2aSThomas Huth
271bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, superh_cpu_realizefn,
272bf853881SPhilippe Mathieu-Daudé &scc->parent_realize);
273fcf5ef2aSThomas Huth
27490493830SPeter Maydell resettable_class_set_parent_phases(rc, NULL, superh_cpu_reset_hold, NULL,
27590493830SPeter Maydell &scc->parent_phases);
276fcf5ef2aSThomas Huth
277fcf5ef2aSThomas Huth cc->class_by_name = superh_cpu_class_by_name;
278fcf5ef2aSThomas Huth cc->has_work = superh_cpu_has_work;
2799ba49d72SRichard Henderson cc->mmu_index = sh4_cpu_mmu_index;
280fcf5ef2aSThomas Huth cc->dump_state = superh_cpu_dump_state;
281fcf5ef2aSThomas Huth cc->set_pc = superh_cpu_set_pc;
282e4fdf9dfSRichard Henderson cc->get_pc = superh_cpu_get_pc;
283fcf5ef2aSThomas Huth cc->gdb_read_register = superh_cpu_gdb_read_register;
284fcf5ef2aSThomas Huth cc->gdb_write_register = superh_cpu_gdb_write_register;
285f98bce2bSRichard Henderson #ifndef CONFIG_USER_ONLY
2868b80bd28SPhilippe Mathieu-Daudé cc->sysemu_ops = &sh4_sysemu_ops;
2874336073bSPhilippe Mathieu-Daudé dc->vmsd = &vmstate_sh_cpu;
288fcf5ef2aSThomas Huth #endif
289fcf5ef2aSThomas Huth cc->disas_set_info = superh_cpu_disas_set_info;
290fcf5ef2aSThomas Huth
291fcf5ef2aSThomas Huth cc->gdb_num_core_regs = 59;
29278271684SClaudio Fontana cc->tcg_ops = &superh_tcg_ops;
293fcf5ef2aSThomas Huth }
294fcf5ef2aSThomas Huth
295974e58d2SIgor Mammedov #define DEFINE_SUPERH_CPU_TYPE(type_name, cinit, initfn) \
296974e58d2SIgor Mammedov { \
297974e58d2SIgor Mammedov .name = type_name, \
298974e58d2SIgor Mammedov .parent = TYPE_SUPERH_CPU, \
299974e58d2SIgor Mammedov .class_init = cinit, \
300974e58d2SIgor Mammedov .instance_init = initfn, \
301974e58d2SIgor Mammedov }
302974e58d2SIgor Mammedov static const TypeInfo superh_cpu_type_infos[] = {
303974e58d2SIgor Mammedov {
304fcf5ef2aSThomas Huth .name = TYPE_SUPERH_CPU,
305fcf5ef2aSThomas Huth .parent = TYPE_CPU,
306fcf5ef2aSThomas Huth .instance_size = sizeof(SuperHCPU),
307f669c992SRichard Henderson .instance_align = __alignof(SuperHCPU),
308fcf5ef2aSThomas Huth .instance_init = superh_cpu_initfn,
309fcf5ef2aSThomas Huth .abstract = true,
310fcf5ef2aSThomas Huth .class_size = sizeof(SuperHCPUClass),
311fcf5ef2aSThomas Huth .class_init = superh_cpu_class_init,
312974e58d2SIgor Mammedov },
313974e58d2SIgor Mammedov DEFINE_SUPERH_CPU_TYPE(TYPE_SH7750R_CPU, sh7750r_class_init,
314974e58d2SIgor Mammedov sh7750r_cpu_initfn),
315974e58d2SIgor Mammedov DEFINE_SUPERH_CPU_TYPE(TYPE_SH7751R_CPU, sh7751r_class_init,
316974e58d2SIgor Mammedov sh7751r_cpu_initfn),
317974e58d2SIgor Mammedov DEFINE_SUPERH_CPU_TYPE(TYPE_SH7785_CPU, sh7785_class_init,
318974e58d2SIgor Mammedov sh7785_cpu_initfn),
319974e58d2SIgor Mammedov
320fcf5ef2aSThomas Huth };
321fcf5ef2aSThomas Huth
322974e58d2SIgor Mammedov DEFINE_TYPES(superh_cpu_type_infos)
323