root / target-openrisc / cpu.c @ a1ebd6ce
History | View | Annotate | Download (6 kB)
1 |
/*
|
---|---|
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() */
|
24 |
static void openrisc_cpu_reset(CPUState *s) |
25 |
{ |
26 |
OpenRISCCPU *cpu = OPENRISC_CPU(s); |
27 |
OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(cpu); |
28 |
|
29 |
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
|
30 |
qemu_log("CPU Reset (CPU %d)\n", s->cpu_index);
|
31 |
log_cpu_state(&cpu->env, 0);
|
32 |
} |
33 |
|
34 |
occ->parent_reset(s); |
35 |
|
36 |
memset(&cpu->env, 0, offsetof(CPUOpenRISCState, breakpoints));
|
37 |
|
38 |
tlb_flush(&cpu->env, 1);
|
39 |
/*tb_flush(&cpu->env); FIXME: Do we need it? */
|
40 |
|
41 |
cpu->env.pc = 0x100;
|
42 |
cpu->env.sr = SR_FO | SR_SM; |
43 |
cpu->env.exception_index = -1;
|
44 |
|
45 |
cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP; |
46 |
cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S; |
47 |
cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2)); |
48 |
cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2)); |
49 |
|
50 |
#ifndef CONFIG_USER_ONLY
|
51 |
cpu->env.picmr = 0x00000000;
|
52 |
cpu->env.picsr = 0x00000000;
|
53 |
|
54 |
cpu->env.ttmr = 0x00000000;
|
55 |
cpu->env.ttcr = 0x00000000;
|
56 |
#endif
|
57 |
} |
58 |
|
59 |
static inline void set_feature(OpenRISCCPU *cpu, int feature) |
60 |
{ |
61 |
cpu->feature |= feature; |
62 |
cpu->env.cpucfgr = cpu->feature; |
63 |
} |
64 |
|
65 |
void openrisc_cpu_realize(Object *obj, Error **errp)
|
66 |
{ |
67 |
OpenRISCCPU *cpu = OPENRISC_CPU(obj); |
68 |
|
69 |
qemu_init_vcpu(&cpu->env); |
70 |
cpu_reset(CPU(cpu)); |
71 |
} |
72 |
|
73 |
static void openrisc_cpu_initfn(Object *obj) |
74 |
{ |
75 |
OpenRISCCPU *cpu = OPENRISC_CPU(obj); |
76 |
static int inited; |
77 |
|
78 |
cpu_exec_init(&cpu->env); |
79 |
|
80 |
#ifndef CONFIG_USER_ONLY
|
81 |
cpu_openrisc_mmu_init(cpu); |
82 |
#endif
|
83 |
|
84 |
if (tcg_enabled() && !inited) {
|
85 |
inited = 1;
|
86 |
openrisc_translate_init(); |
87 |
} |
88 |
} |
89 |
|
90 |
/* CPU models */
|
91 |
|
92 |
static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model) |
93 |
{ |
94 |
ObjectClass *oc; |
95 |
|
96 |
if (cpu_model == NULL) { |
97 |
return NULL; |
98 |
} |
99 |
|
100 |
oc = object_class_by_name(cpu_model); |
101 |
if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU) || |
102 |
object_class_is_abstract(oc))) { |
103 |
return NULL; |
104 |
} |
105 |
return oc;
|
106 |
} |
107 |
|
108 |
static void or1200_initfn(Object *obj) |
109 |
{ |
110 |
OpenRISCCPU *cpu = OPENRISC_CPU(obj); |
111 |
|
112 |
set_feature(cpu, OPENRISC_FEATURE_OB32S); |
113 |
set_feature(cpu, OPENRISC_FEATURE_OF32S); |
114 |
} |
115 |
|
116 |
static void openrisc_any_initfn(Object *obj) |
117 |
{ |
118 |
OpenRISCCPU *cpu = OPENRISC_CPU(obj); |
119 |
|
120 |
set_feature(cpu, OPENRISC_FEATURE_OB32S); |
121 |
} |
122 |
|
123 |
typedef struct OpenRISCCPUInfo { |
124 |
const char *name; |
125 |
void (*initfn)(Object *obj);
|
126 |
} OpenRISCCPUInfo; |
127 |
|
128 |
static const OpenRISCCPUInfo openrisc_cpus[] = { |
129 |
{ .name = "or1200", .initfn = or1200_initfn },
|
130 |
{ .name = "any", .initfn = openrisc_any_initfn },
|
131 |
}; |
132 |
|
133 |
static void openrisc_cpu_class_init(ObjectClass *oc, void *data) |
134 |
{ |
135 |
OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc); |
136 |
CPUClass *cc = CPU_CLASS(occ); |
137 |
|
138 |
occ->parent_reset = cc->reset; |
139 |
cc->reset = openrisc_cpu_reset; |
140 |
|
141 |
cc->class_by_name = openrisc_cpu_class_by_name; |
142 |
} |
143 |
|
144 |
static void cpu_register(const OpenRISCCPUInfo *info) |
145 |
{ |
146 |
TypeInfo type_info = { |
147 |
.name = info->name, |
148 |
.parent = TYPE_OPENRISC_CPU, |
149 |
.instance_size = sizeof(OpenRISCCPU),
|
150 |
.instance_init = info->initfn, |
151 |
.class_size = sizeof(OpenRISCCPUClass),
|
152 |
}; |
153 |
|
154 |
type_register(&type_info); |
155 |
} |
156 |
|
157 |
static const TypeInfo openrisc_cpu_type_info = { |
158 |
.name = TYPE_OPENRISC_CPU, |
159 |
.parent = TYPE_CPU, |
160 |
.instance_size = sizeof(OpenRISCCPU),
|
161 |
.instance_init = openrisc_cpu_initfn, |
162 |
.abstract = false,
|
163 |
.class_size = sizeof(OpenRISCCPUClass),
|
164 |
.class_init = openrisc_cpu_class_init, |
165 |
}; |
166 |
|
167 |
static void openrisc_cpu_register_types(void) |
168 |
{ |
169 |
int i;
|
170 |
|
171 |
type_register_static(&openrisc_cpu_type_info); |
172 |
for (i = 0; i < ARRAY_SIZE(openrisc_cpus); i++) { |
173 |
cpu_register(&openrisc_cpus[i]); |
174 |
} |
175 |
} |
176 |
|
177 |
OpenRISCCPU *cpu_openrisc_init(const char *cpu_model) |
178 |
{ |
179 |
OpenRISCCPU *cpu; |
180 |
ObjectClass *oc; |
181 |
|
182 |
oc = openrisc_cpu_class_by_name(cpu_model); |
183 |
if (oc == NULL) { |
184 |
return NULL; |
185 |
} |
186 |
cpu = OPENRISC_CPU(object_new(object_class_get_name(oc))); |
187 |
cpu->env.cpu_model_str = cpu_model; |
188 |
|
189 |
openrisc_cpu_realize(OBJECT(cpu), NULL);
|
190 |
|
191 |
return cpu;
|
192 |
} |
193 |
|
194 |
/* Sort alphabetically by type name, except for "any". */
|
195 |
static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b)
|
196 |
{ |
197 |
ObjectClass *class_a = (ObjectClass *)a; |
198 |
ObjectClass *class_b = (ObjectClass *)b; |
199 |
const char *name_a, *name_b; |
200 |
|
201 |
name_a = object_class_get_name(class_a); |
202 |
name_b = object_class_get_name(class_b); |
203 |
if (strcmp(name_a, "any") == 0) { |
204 |
return 1; |
205 |
} else if (strcmp(name_b, "any") == 0) { |
206 |
return -1; |
207 |
} else {
|
208 |
return strcmp(name_a, name_b);
|
209 |
} |
210 |
} |
211 |
|
212 |
static void openrisc_cpu_list_entry(gpointer data, gpointer user_data) |
213 |
{ |
214 |
ObjectClass *oc = data; |
215 |
CPUListState *s = user_data; |
216 |
|
217 |
(*s->cpu_fprintf)(s->file, " %s\n",
|
218 |
object_class_get_name(oc)); |
219 |
} |
220 |
|
221 |
void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf)
|
222 |
{ |
223 |
CPUListState s = { |
224 |
.file = f, |
225 |
.cpu_fprintf = cpu_fprintf, |
226 |
}; |
227 |
GSList *list; |
228 |
|
229 |
list = object_class_get_list(TYPE_OPENRISC_CPU, false);
|
230 |
list = g_slist_sort(list, openrisc_cpu_list_compare); |
231 |
(*cpu_fprintf)(f, "Available CPUs:\n");
|
232 |
g_slist_foreach(list, openrisc_cpu_list_entry, &s); |
233 |
g_slist_free(list); |
234 |
} |
235 |
|
236 |
type_init(openrisc_cpu_register_types) |