aboutsummaryrefslogtreecommitdiff
path: root/target-sh4/cpu.c
diff options
context:
space:
mode:
authorAndreas Färber <afaerber@suse.de>2012-11-19 02:42:18 +0100
committerAndreas Färber <afaerber@suse.de>2013-03-12 10:35:54 +0100
commitc1b382e77d8693955d8838c19b33aeb214724f9b (patch)
tree30d4c1ba5a13e2e5335e680a2fbc99217e31a403 /target-sh4/cpu.c
parent151d1322a3a0c865089c09aeb50f18215121921a (diff)
target-sh4: Introduce SuperHCPU subclasses
Store legacy name in SuperHCPUClass for -cpu ? and for case-insensitive class lookup. List CPUs by iterating over TYPE_SUPERH_CPU subclasses. Signed-off-by: Andreas Färber <afaerber@suse.de>
Diffstat (limited to 'target-sh4/cpu.c')
-rw-r--r--target-sh4/cpu.c180
1 files changed, 179 insertions, 1 deletions
diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c
index ef0e62195d..fba1534f86 100644
--- a/target-sh4/cpu.c
+++ b/target-sh4/cpu.c
@@ -54,6 +54,180 @@ static void superh_cpu_reset(CPUState *s)
set_default_nan_mode(1, &env->fp_status);
}
+typedef struct SuperHCPUListState {
+ fprintf_function cpu_fprintf;
+ FILE *file;
+} SuperHCPUListState;
+
+/* Sort alphabetically by type name. */
+static gint superh_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+ ObjectClass *class_a = (ObjectClass *)a;
+ ObjectClass *class_b = (ObjectClass *)b;
+ const char *name_a, *name_b;
+
+ name_a = object_class_get_name(class_a);
+ name_b = object_class_get_name(class_b);
+ return strcmp(name_a, name_b);
+}
+
+static void superh_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+ SuperHCPUListState *s = user_data;
+
+ (*s->cpu_fprintf)(s->file, "%s\n",
+ scc->name);
+}
+
+void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ SuperHCPUListState s = {
+ .cpu_fprintf = cpu_fprintf,
+ .file = f,
+ };
+ GSList *list;
+
+ list = object_class_get_list(TYPE_SUPERH_CPU, false);
+ list = g_slist_sort(list, superh_cpu_list_compare);
+ g_slist_foreach(list, superh_cpu_list_entry, &s);
+ g_slist_free(list);
+}
+
+static gint superh_cpu_name_compare(gconstpointer a, gconstpointer b)
+{
+ const SuperHCPUClass *scc = SUPERH_CPU_CLASS(a);
+ const char *name = b;
+
+ return strcasecmp(scc->name, name);
+}
+
+static ObjectClass *superh_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ GSList *list, *item;
+
+ if (cpu_model == NULL) {
+ return NULL;
+ }
+ if (strcasecmp(cpu_model, "any") == 0) {
+ return object_class_by_name(TYPE_SH7750R_CPU);
+ }
+
+ oc = object_class_by_name(cpu_model);
+ if (oc != NULL && object_class_dynamic_cast(oc, TYPE_SUPERH_CPU) != NULL
+ && !object_class_is_abstract(oc)) {
+ return oc;
+ }
+
+ oc = NULL;
+ list = object_class_get_list(TYPE_SUPERH_CPU, false);
+ item = g_slist_find_custom(list, cpu_model, superh_cpu_name_compare);
+ if (item != NULL) {
+ oc = item->data;
+ }
+ g_slist_free(list);
+ return oc;
+}
+
+SuperHCPU *cpu_sh4_init(const char *cpu_model)
+{
+ SuperHCPU *cpu;
+ CPUSH4State *env;
+ ObjectClass *oc;
+
+ oc = superh_cpu_class_by_name(cpu_model);
+ if (oc == NULL) {
+ return NULL;
+ }
+ cpu = SUPERH_CPU(object_new(object_class_get_name(oc)));
+ env = &cpu->env;
+ env->cpu_model_str = cpu_model;
+
+ object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
+
+ return cpu;
+}
+
+static void sh7750r_cpu_initfn(Object *obj)
+{
+ SuperHCPU *cpu = SUPERH_CPU(obj);
+ CPUSH4State *env = &cpu->env;
+
+ env->id = SH_CPU_SH7750R;
+ env->pvr = 0x00050000;
+ env->prr = 0x00000100;
+ env->cvr = 0x00110000;
+ env->features = SH_FEATURE_BCR3_AND_BCR4;
+}
+
+static void sh7750r_class_init(ObjectClass *oc, void *data)
+{
+ SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+
+ scc->name = "SH7750R";
+}
+
+static const TypeInfo sh7750r_type_info = {
+ .name = TYPE_SH7750R_CPU,
+ .parent = TYPE_SUPERH_CPU,
+ .class_init = sh7750r_class_init,
+ .instance_init = sh7750r_cpu_initfn,
+};
+
+static void sh7751r_cpu_initfn(Object *obj)
+{
+ SuperHCPU *cpu = SUPERH_CPU(obj);
+ CPUSH4State *env = &cpu->env;
+
+ env->id = SH_CPU_SH7751R;
+ env->pvr = 0x04050005;
+ env->prr = 0x00000113;
+ env->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */
+ env->features = SH_FEATURE_BCR3_AND_BCR4;
+}
+
+static void sh7751r_class_init(ObjectClass *oc, void *data)
+{
+ SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+
+ scc->name = "SH7751R";
+}
+
+static const TypeInfo sh7751r_type_info = {
+ .name = TYPE_SH7751R_CPU,
+ .parent = TYPE_SUPERH_CPU,
+ .class_init = sh7751r_class_init,
+ .instance_init = sh7751r_cpu_initfn,
+};
+
+static void sh7785_cpu_initfn(Object *obj)
+{
+ SuperHCPU *cpu = SUPERH_CPU(obj);
+ CPUSH4State *env = &cpu->env;
+
+ env->id = SH_CPU_SH7785;
+ env->pvr = 0x10300700;
+ env->prr = 0x00000200;
+ env->cvr = 0x71440211;
+ env->features = SH_FEATURE_SH4A;
+}
+
+static void sh7785_class_init(ObjectClass *oc, void *data)
+{
+ SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc);
+
+ scc->name = "SH7785";
+}
+
+static const TypeInfo sh7785_type_info = {
+ .name = TYPE_SH7785_CPU,
+ .parent = TYPE_SUPERH_CPU,
+ .class_init = sh7785_class_init,
+ .instance_init = sh7785_cpu_initfn,
+};
+
static void superh_cpu_realizefn(DeviceState *dev, Error **errp)
{
SuperHCPU *cpu = SUPERH_CPU(dev);
@@ -98,6 +272,7 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
scc->parent_reset = cc->reset;
cc->reset = superh_cpu_reset;
+ cc->class_by_name = superh_cpu_class_by_name;
dc->vmsd = &vmstate_sh_cpu;
}
@@ -106,7 +281,7 @@ static const TypeInfo superh_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(SuperHCPU),
.instance_init = superh_cpu_initfn,
- .abstract = false,
+ .abstract = true,
.class_size = sizeof(SuperHCPUClass),
.class_init = superh_cpu_class_init,
};
@@ -114,6 +289,9 @@ static const TypeInfo superh_cpu_type_info = {
static void superh_cpu_register_types(void)
{
type_register_static(&superh_cpu_type_info);
+ type_register_static(&sh7750r_type_info);
+ type_register_static(&sh7751r_type_info);
+ type_register_static(&sh7785_type_info);
}
type_init(superh_cpu_register_types)