diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h index f4e8976478..19d8b084ff 100644 --- a/target-sh4/cpu-qom.h +++ b/target-sh4/cpu-qom.h @@ -24,6 +24,10 @@ #define TYPE_SUPERH_CPU "superh-cpu" +#define TYPE_SH7750R_CPU "sh7750r-" TYPE_SUPERH_CPU +#define TYPE_SH7751R_CPU "sh7751r-" TYPE_SUPERH_CPU +#define TYPE_SH7785_CPU "sh7785-" TYPE_SUPERH_CPU + #define SUPERH_CPU_CLASS(klass) \ OBJECT_CLASS_CHECK(SuperHCPUClass, (klass), TYPE_SUPERH_CPU) #define SUPERH_CPU(obj) \ @@ -35,6 +39,7 @@ * SuperHCPUClass: * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. + * @name: The name. * * A SuperH CPU model. */ @@ -45,6 +50,8 @@ typedef struct SuperHCPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); + + const char *name; } SuperHCPUClass; /** 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) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 7f300e3444..14fdb8fc2d 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -175,90 +175,6 @@ void cpu_dump_state(CPUSH4State * env, FILE * f, } } -typedef struct { - const char *name; - int id; - uint32_t pvr; - uint32_t prr; - uint32_t cvr; - uint32_t features; -} sh4_def_t; - -static sh4_def_t sh4_defs[] = { - { - .name = "SH7750R", - .id = SH_CPU_SH7750R, - .pvr = 0x00050000, - .prr = 0x00000100, - .cvr = 0x00110000, - .features = SH_FEATURE_BCR3_AND_BCR4, - }, { - .name = "SH7751R", - .id = SH_CPU_SH7751R, - .pvr = 0x04050005, - .prr = 0x00000113, - .cvr = 0x00110000, /* Neutered caches, should be 0x20480000 */ - .features = SH_FEATURE_BCR3_AND_BCR4, - }, { - .name = "SH7785", - .id = SH_CPU_SH7785, - .pvr = 0x10300700, - .prr = 0x00000200, - .cvr = 0x71440211, - .features = SH_FEATURE_SH4A, - }, -}; - -static const sh4_def_t *cpu_sh4_find_by_name(const char *name) -{ - int i; - - if (strcasecmp(name, "any") == 0) - return &sh4_defs[0]; - - for (i = 0; i < ARRAY_SIZE(sh4_defs); i++) - if (strcasecmp(name, sh4_defs[i].name) == 0) - return &sh4_defs[i]; - - return NULL; -} - -void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sh4_defs); i++) - (*cpu_fprintf)(f, "%s\n", sh4_defs[i].name); -} - -static void cpu_register(CPUSH4State *env, const sh4_def_t *def) -{ - env->pvr = def->pvr; - env->prr = def->prr; - env->cvr = def->cvr; - env->id = def->id; -} - -SuperHCPU *cpu_sh4_init(const char *cpu_model) -{ - SuperHCPU *cpu; - CPUSH4State *env; - const sh4_def_t *def; - - def = cpu_sh4_find_by_name(cpu_model); - if (!def) - return NULL; - cpu = SUPERH_CPU(object_new(TYPE_SUPERH_CPU)); - env = &cpu->env; - env->features = def->features; - env->cpu_model_str = cpu_model; - cpu_register(env, def); - - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - - return cpu; -} - static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) { TranslationBlock *tb;