blob: e348df0fef8668690a4532ef1e35d3b261e3ac78 [file] [log] [blame]
Jia Liue67db062012-07-20 15:50:39 +08001/*
2 * QEMU OpenRISC CPU
3 *
4 * Copyright (c) 2012 Jia Liu <proljc@gmail.com>
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 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 <http://www.gnu.org/licenses/>.
18 */
19
20#include "cpu.h"
21#include "qemu-common.h"
22
23/* CPUClass::reset() */
24static void openrisc_cpu_reset(CPUState *s)
25{
26 OpenRISCCPU *cpu = OPENRISC_CPU(s);
27 OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(cpu);
28
Jia Liue67db062012-07-20 15:50:39 +080029 occ->parent_reset(s);
30
31 memset(&cpu->env, 0, offsetof(CPUOpenRISCState, breakpoints));
32
33 tlb_flush(&cpu->env, 1);
34 /*tb_flush(&cpu->env); FIXME: Do we need it? */
35
36 cpu->env.pc = 0x100;
37 cpu->env.sr = SR_FO | SR_SM;
38 cpu->env.exception_index = -1;
39
40 cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP;
41 cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S;
42 cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2));
43 cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2));
44
45#ifndef CONFIG_USER_ONLY
46 cpu->env.picmr = 0x00000000;
47 cpu->env.picsr = 0x00000000;
48
49 cpu->env.ttmr = 0x00000000;
50 cpu->env.ttcr = 0x00000000;
51#endif
52}
53
54static inline void set_feature(OpenRISCCPU *cpu, int feature)
55{
56 cpu->feature |= feature;
57 cpu->env.cpucfgr = cpu->feature;
58}
59
Andreas Färberc2962622013-01-05 14:11:07 +010060static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp)
Jia Liue67db062012-07-20 15:50:39 +080061{
Andreas Färberc2962622013-01-05 14:11:07 +010062 OpenRISCCPU *cpu = OPENRISC_CPU(dev);
63 OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(dev);
Jia Liue67db062012-07-20 15:50:39 +080064
Jia Liue67db062012-07-20 15:50:39 +080065 cpu_reset(CPU(cpu));
Andreas Färberc2962622013-01-05 14:11:07 +010066
67 occ->parent_realize(dev, errp);
Jia Liue67db062012-07-20 15:50:39 +080068}
69
70static void openrisc_cpu_initfn(Object *obj)
71{
Andreas Färberc05efcb2013-01-17 12:13:41 +010072 CPUState *cs = CPU(obj);
Jia Liue67db062012-07-20 15:50:39 +080073 OpenRISCCPU *cpu = OPENRISC_CPU(obj);
74 static int inited;
75
Andreas Färberc05efcb2013-01-17 12:13:41 +010076 cs->env_ptr = &cpu->env;
Jia Liue67db062012-07-20 15:50:39 +080077 cpu_exec_init(&cpu->env);
78
79#ifndef CONFIG_USER_ONLY
80 cpu_openrisc_mmu_init(cpu);
81#endif
82
83 if (tcg_enabled() && !inited) {
84 inited = 1;
85 openrisc_translate_init();
86 }
87}
88
89/* CPU models */
Andreas Färberbd039ce2013-01-23 11:17:14 +010090
91static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model)
92{
93 ObjectClass *oc;
Dongxue Zhang071b3362013-07-02 17:11:55 +080094 char *typename;
Andreas Färberbd039ce2013-01-23 11:17:14 +010095
96 if (cpu_model == NULL) {
97 return NULL;
98 }
99
Dongxue Zhang071b3362013-07-02 17:11:55 +0800100 typename = g_strdup_printf("%s-" TYPE_OPENRISC_CPU, cpu_model);
101 oc = object_class_by_name(typename);
Jia Liu9b146e92013-07-23 18:32:30 +0800102 g_free(typename);
Andreas Färberc432b782013-01-23 12:39:38 +0100103 if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU) ||
104 object_class_is_abstract(oc))) {
Andreas Färberbd039ce2013-01-23 11:17:14 +0100105 return NULL;
106 }
107 return oc;
108}
109
Jia Liue67db062012-07-20 15:50:39 +0800110static void or1200_initfn(Object *obj)
111{
112 OpenRISCCPU *cpu = OPENRISC_CPU(obj);
113
114 set_feature(cpu, OPENRISC_FEATURE_OB32S);
115 set_feature(cpu, OPENRISC_FEATURE_OF32S);
116}
117
118static void openrisc_any_initfn(Object *obj)
119{
120 OpenRISCCPU *cpu = OPENRISC_CPU(obj);
121
122 set_feature(cpu, OPENRISC_FEATURE_OB32S);
123}
124
125typedef struct OpenRISCCPUInfo {
126 const char *name;
127 void (*initfn)(Object *obj);
128} OpenRISCCPUInfo;
129
130static const OpenRISCCPUInfo openrisc_cpus[] = {
131 { .name = "or1200", .initfn = or1200_initfn },
132 { .name = "any", .initfn = openrisc_any_initfn },
133};
134
135static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
136{
137 OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc);
138 CPUClass *cc = CPU_CLASS(occ);
Andreas Färberc2962622013-01-05 14:11:07 +0100139 DeviceClass *dc = DEVICE_CLASS(oc);
140
141 occ->parent_realize = dc->realize;
142 dc->realize = openrisc_cpu_realizefn;
Jia Liue67db062012-07-20 15:50:39 +0800143
144 occ->parent_reset = cc->reset;
145 cc->reset = openrisc_cpu_reset;
Andreas Färberbd039ce2013-01-23 11:17:14 +0100146
147 cc->class_by_name = openrisc_cpu_class_by_name;
Andreas Färber97a8ea52013-02-02 10:57:51 +0100148 cc->do_interrupt = openrisc_cpu_do_interrupt;
Andreas Färber878096e2013-05-27 01:33:50 +0200149 cc->dump_state = openrisc_cpu_dump_state;
Andreas Färberda697212013-02-02 13:59:05 +0100150 device_class_set_vmsd(dc, &vmstate_openrisc_cpu);
Jia Liue67db062012-07-20 15:50:39 +0800151}
152
153static void cpu_register(const OpenRISCCPUInfo *info)
154{
155 TypeInfo type_info = {
Jia Liue67db062012-07-20 15:50:39 +0800156 .parent = TYPE_OPENRISC_CPU,
157 .instance_size = sizeof(OpenRISCCPU),
158 .instance_init = info->initfn,
159 .class_size = sizeof(OpenRISCCPUClass),
160 };
161
Andreas Färber478032a2013-01-27 22:50:35 +0100162 type_info.name = g_strdup_printf("%s-" TYPE_OPENRISC_CPU, info->name);
Andreas Färbera1ebd6c2013-01-23 11:10:14 +0100163 type_register(&type_info);
Andreas Färber478032a2013-01-27 22:50:35 +0100164 g_free((void *)type_info.name);
Jia Liue67db062012-07-20 15:50:39 +0800165}
166
167static const TypeInfo openrisc_cpu_type_info = {
168 .name = TYPE_OPENRISC_CPU,
169 .parent = TYPE_CPU,
170 .instance_size = sizeof(OpenRISCCPU),
171 .instance_init = openrisc_cpu_initfn,
Andreas Färberbc755a02013-01-27 22:27:17 +0100172 .abstract = true,
Jia Liue67db062012-07-20 15:50:39 +0800173 .class_size = sizeof(OpenRISCCPUClass),
174 .class_init = openrisc_cpu_class_init,
175};
176
177static void openrisc_cpu_register_types(void)
178{
179 int i;
180
181 type_register_static(&openrisc_cpu_type_info);
182 for (i = 0; i < ARRAY_SIZE(openrisc_cpus); i++) {
183 cpu_register(&openrisc_cpus[i]);
184 }
185}
186
187OpenRISCCPU *cpu_openrisc_init(const char *cpu_model)
188{
189 OpenRISCCPU *cpu;
Andreas Färberbd039ce2013-01-23 11:17:14 +0100190 ObjectClass *oc;
Jia Liue67db062012-07-20 15:50:39 +0800191
Andreas Färberbd039ce2013-01-23 11:17:14 +0100192 oc = openrisc_cpu_class_by_name(cpu_model);
193 if (oc == NULL) {
Jia Liue67db062012-07-20 15:50:39 +0800194 return NULL;
195 }
Andreas Färberbd039ce2013-01-23 11:17:14 +0100196 cpu = OPENRISC_CPU(object_new(object_class_get_name(oc)));
Jia Liue67db062012-07-20 15:50:39 +0800197 cpu->env.cpu_model_str = cpu_model;
198
Andreas Färberc2962622013-01-05 14:11:07 +0100199 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
Jia Liue67db062012-07-20 15:50:39 +0800200
201 return cpu;
202}
203
Jia Liue67db062012-07-20 15:50:39 +0800204/* Sort alphabetically by type name, except for "any". */
205static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b)
206{
207 ObjectClass *class_a = (ObjectClass *)a;
208 ObjectClass *class_b = (ObjectClass *)b;
209 const char *name_a, *name_b;
210
211 name_a = object_class_get_name(class_a);
212 name_b = object_class_get_name(class_b);
Andreas Färber478032a2013-01-27 22:50:35 +0100213 if (strcmp(name_a, "any-" TYPE_OPENRISC_CPU) == 0) {
Jia Liue67db062012-07-20 15:50:39 +0800214 return 1;
Andreas Färber478032a2013-01-27 22:50:35 +0100215 } else if (strcmp(name_b, "any-" TYPE_OPENRISC_CPU) == 0) {
Jia Liue67db062012-07-20 15:50:39 +0800216 return -1;
217 } else {
218 return strcmp(name_a, name_b);
219 }
220}
221
222static void openrisc_cpu_list_entry(gpointer data, gpointer user_data)
223{
224 ObjectClass *oc = data;
Andreas Färber8486af92013-01-05 14:14:27 +0100225 CPUListState *s = user_data;
Andreas Färber478032a2013-01-27 22:50:35 +0100226 const char *typename;
227 char *name;
Jia Liue67db062012-07-20 15:50:39 +0800228
Andreas Färber478032a2013-01-27 22:50:35 +0100229 typename = object_class_get_name(oc);
230 name = g_strndup(typename,
231 strlen(typename) - strlen("-" TYPE_OPENRISC_CPU));
Jia Liue67db062012-07-20 15:50:39 +0800232 (*s->cpu_fprintf)(s->file, " %s\n",
Andreas Färber478032a2013-01-27 22:50:35 +0100233 name);
234 g_free(name);
Jia Liue67db062012-07-20 15:50:39 +0800235}
236
237void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf)
238{
Andreas Färber8486af92013-01-05 14:14:27 +0100239 CPUListState s = {
Jia Liue67db062012-07-20 15:50:39 +0800240 .file = f,
241 .cpu_fprintf = cpu_fprintf,
242 };
243 GSList *list;
244
245 list = object_class_get_list(TYPE_OPENRISC_CPU, false);
246 list = g_slist_sort(list, openrisc_cpu_list_compare);
247 (*cpu_fprintf)(f, "Available CPUs:\n");
248 g_slist_foreach(list, openrisc_cpu_list_entry, &s);
249 g_slist_free(list);
250}
251
252type_init(openrisc_cpu_register_types)