CR16C: Clean up boards

Implement a generic virt board and the basic structure for the Gigaset DE410 board.
This commit is contained in:
Jonas Bewig 2025-08-14 10:39:59 +02:00
parent 8c748ec01a
commit 3fc0f53606
No known key found for this signature in database
GPG key ID: 8D99867797A4886F
21 changed files with 271 additions and 213 deletions

View file

@ -1,4 +1,5 @@
# Default configuration for cr16c-softmmu
# Boards:
#
CONFIG_SC14450=y
CONFIG_VIRT=y
CONFIG_DE410=y

View file

@ -1,2 +1,5 @@
config SC14450
config VIRT
bool
config DE410
bool

View file

@ -3,7 +3,7 @@
#include "qemu/datadir.h"
#include "qemu/error-report.h"
bool cr16c_load_firmware(CR16CCPU *cpu, MachineState *ms, MemoryRegion *mr, const char *firmware) {
bool cr16c_load_firmware(CR16CCPU *cpu, MemoryRegion *mr, const char *firmware) {
/* Adapted from arm implementation */
g_autofree char *filename = NULL;
int ret;

View file

@ -3,6 +3,6 @@
#include "target/cr16c/cpu.h"
bool cr16c_load_firmware(CR16CCPU *cpu, MachineState *ms, MemoryRegion *mr, const char *firmware);
bool cr16c_load_firmware(CR16CCPU *cpu, MemoryRegion *mr, const char *firmware);
#endif /* HW_CR16C_BOOT_H */

62
hw/cr16c/de410.c Normal file
View file

@ -0,0 +1,62 @@
#include "boot.h"
#include "exec/memory.h"
#include "hw/boards.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
#include "qemu/units.h"
#include "qom/object.h"
#include "sc14461.h"
typedef struct DE410MachineState {
MachineState parent_obj;
SC14461McuState mcu;
MemoryRegion firmware;
} DE410MachineState;
typedef struct DE410MachineClass {
MachineClass parent_class;
} DE410MachineClass;
#define TYPE_DE410_MACHINE MACHINE_TYPE_NAME("de410")
DECLARE_OBJ_CHECKERS(DE410MachineState, DE410MachineClass, DE410_MACHINE, TYPE_DE410_MACHINE)
static void de410_init(MachineState* machine)
{
DE410MachineState* m_state = DE410_MACHINE(machine);
object_initialize_child(OBJECT(machine), "mcu", &m_state->mcu, TYPE_SC14461_MCU);
sysbus_realize(SYS_BUS_DEVICE(&m_state->mcu), &error_abort);
// Provide an option to load a small program until the peripherals are implemented
if (machine->firmware) {
memory_region_init_ram(&m_state->firmware, NULL, "firmware", (0xA000-0x8080)*KiB, &error_fatal);
memory_region_add_subregion(&m_state->mcu.non_shared_ram_or_dcache, 0x80, &m_state->firmware);
cr16c_load_firmware(&m_state->mcu.cpu, &m_state->firmware, machine->firmware);
}
}
static void de410_class_init(ObjectClass* oc, void* data)
{
MachineClass* mc = MACHINE_CLASS(oc);
mc->desc = "DE410 VoIP desk telephone by Gigaset";
mc->init = de410_init;
mc->default_cpus = 1;
mc->min_cpus = 1;
mc->max_cpus = 1;
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
}
static const TypeInfo de410_machine_types[] = {
{
.name = TYPE_DE410_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(DE410MachineState),
.class_size = sizeof(DE410MachineClass),
.class_init = de410_class_init,
}
};
DEFINE_TYPES(de410_machine_types);

View file

@ -1,5 +1,6 @@
cr16c_ss = ss.source_set()
cr16c_ss.add(files('sc14450.c'))
cr16c_ss.add(files('sc14450board.c'))
cr16c_ss.add(files('virt.c'))
cr16c_ss.add(files('sc14461.c'))
cr16c_ss.add(files('de410.c'))
cr16c_ss.add(files('boot.c'))
hw_arch += {'cr16c': cr16c_ss}

View file

@ -1,56 +0,0 @@
#include "sc14450.h"
#include "exec/address-spaces.h"
#include "qapi/error.h"
#include "qemu/units.h"
typedef struct SC14450McuClass {
SysBusDeviceClass parent_class;
const char* cpu_type;
size_t flash_size;
} SC14450McuClass;
DECLARE_CLASS_CHECKERS(SC14450McuClass, SC14450_MCU, TYPE_SC14450_MCU)
static void sc14450_realize(DeviceState* dev, Error** errp)
{
SC14450McuState* s = SC14450_MCU(dev);
const SC14450McuClass* mc = SC14450_MCU_GET_CLASS(dev);
object_initialize_child(OBJECT(dev), "cpu", &s->cpu, mc->cpu_type);
object_property_set_bool(OBJECT(&s->cpu), "realized", true, &error_abort);
memory_region_init_ram(&s->flash, OBJECT(dev), "flash", mc->flash_size, &error_fatal);
memory_region_add_subregion(get_system_memory(), 0, &s->flash);
}
static void sc14450_class_init(ObjectClass* oc, void* data)
{
DeviceClass* dc = DEVICE_CLASS(oc);
dc->realize = sc14450_realize;
dc->user_creatable = false;
}
static void sc14450s_class_init(ObjectClass* oc, void* data)
{
SC14450McuClass* sc14450 = SC14450_MCU_CLASS(oc);
sc14450->cpu_type = CR16C_CPU_TYPE_NAME("SC14450C");
sc14450->flash_size = 16 * MiB;
}
static const TypeInfo sc14450_mcu_types[] = {
{
.name = TYPE_SC14450S_MCU,
.parent = TYPE_SC14450_MCU,
.class_init = sc14450s_class_init,
},
{
.name = TYPE_SC14450_MCU,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SC14450McuState),
.class_size = sizeof(SC14450McuClass),
.class_init = sc14450_class_init,
.abstract = true,
}
};
DEFINE_TYPES(sc14450_mcu_types)

View file

@ -1,21 +0,0 @@
#ifndef HW_SC14450_H
#define HW_SC14450_H
#include "target/cr16c/cpu.h"
#include "qom/object.h"
#include "hw/sysbus.h"
#define TYPE_SC14450_MCU "SC14450"
#define TYPE_SC14450S_MCU "SC14450S"
typedef struct SC14450McuState SC14450McuState;
DECLARE_INSTANCE_CHECKER(SC14450McuState, SC14450_MCU, TYPE_SC14450_MCU)
struct SC14450McuState {
SysBusDevice parent_obj;
CR16CCPU cpu;
MemoryRegion flash;
};
#endif /* HW_SC14450_H */

View file

@ -1,60 +0,0 @@
#include "boot.h"
#include "hw/boards.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
#include "qom/object.h"
#include "sc14450.h"
typedef struct SC14450BoardMachineState {
MachineState parent_obj;
SC14450McuState mcu;
} SC14450BoardMachineState;
typedef struct SC14450BoardMachineClass {
MachineClass parent_class;
} SC14450BoardMachineClass;
#define TYPE_SC14450_BOARD_BASE_MACHINE MACHINE_TYPE_NAME("SC14450-board-base")
#define TYPE_SC14450_BOARD_MACHINE MACHINE_TYPE_NAME("SC14450-board")
DECLARE_OBJ_CHECKERS(SC14450BoardMachineState, SC14450BoardMachineClass, SC14450_BOARD_MACHINE, TYPE_SC14450_BOARD_MACHINE)
static void sc14450board_init(MachineState* machine)
{
SC14450BoardMachineState* m_state = SC14450_BOARD_MACHINE(machine);
object_initialize_child(OBJECT(machine), "mcu", &m_state->mcu, TYPE_SC14450S_MCU);
sysbus_realize(SYS_BUS_DEVICE(&m_state->mcu), &error_abort);
if (machine->firmware) {
if (!cr16c_load_firmware(&m_state->mcu.cpu, machine, &m_state->mcu.flash, machine->firmware)) {
exit(1);
}
}
}
static void sc14450board_class_init(ObjectClass* oc, void* data)
{
MachineClass* mc = MACHINE_CLASS(oc);
mc->desc = "SC14450 VoIP + DECT Processor Board";
mc->alias = "sc14450board";
mc->init = sc14450board_init;
mc->default_cpus = 1;
mc->min_cpus = 1;
mc->max_cpus = 1;
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
mc->is_default = 1;
}
static const TypeInfo sc14450board_machine_types[] = {
{
.name = TYPE_SC14450_BOARD_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(SC14450BoardMachineState),
.class_size = sizeof(SC14450BoardMachineClass),
.class_init = sc14450board_class_init,
}
};
DEFINE_TYPES(sc14450board_machine_types);

67
hw/cr16c/sc14461.c Normal file
View file

@ -0,0 +1,67 @@
#include "sc14461.h"
#include "cpu-qom.h"
#include "exec/address-spaces.h"
#include "hw/core/cpu.h"
#include "hw/cr16c/boot.h"
#include "qapi/error.h"
#include "qemu/datadir.h"
#include "qemu/units.h"
static void sc14461_realize(DeviceState* dev, Error** errp)
{
SC14461McuState* s = SC14461_MCU(dev);
object_initialize_child(OBJECT(dev), "cpu", &s->cpu, TYPE_CR16C_CPU);
object_property_set_bool(OBJECT(&s->cpu), "realized", true, &error_abort);
memory_region_init_ram(&s->non_shared_ram_or_icache, OBJECT(dev), "non_shared_ram_or_icache", 24*KiB, &error_fatal);
memory_region_init_ram(&s->non_shared_ram_or_dcache, OBJECT(dev), "non_shared_ram_or_dcache", 8*KiB, &error_fatal);
memory_region_init_ram(&s->shared_int_ram, OBJECT(dev), "shared_int_ram", 64*KiB, &error_fatal);
memory_region_init_rom(&s->boot_rom, OBJECT(dev), "boot_rom", 2*KiB, &error_fatal);
memory_region_add_subregion(get_system_memory(), 0x00000, &s->non_shared_ram_or_icache);
memory_region_add_subregion(get_system_memory(), 0x08000, &s->non_shared_ram_or_dcache);
memory_region_add_subregion(get_system_memory(), 0x10000, &s->shared_int_ram);
memory_region_add_subregion(get_system_memory(), 0xFEF00, &s->boot_rom);
char* bios_path = qemu_find_file(QEMU_FILE_TYPE_BIOS, "sc14461-bios.img");
if (!cr16c_load_firmware(&s->cpu, &s->boot_rom, bios_path)) {
exit(1);
}
}
static void sc14461_reset_hold(Object *obj, ResetType type) {
SC14461McuClass* mcu_class = SC14461_MCU_GET_CLASS(obj);
SC14461McuState* mcu_state = SC14461_MCU(obj);
CR16CCPU* cpu = &mcu_state->cpu;
CPUState* cpu_state = CPU(cpu);
if (mcu_class->parent_phases.hold) {
mcu_class->parent_phases.hold(obj, type);
}
cpu_reset(cpu_state);
cpu_set_pc(cpu_state, 0xFEF00);
}
static void sc14461_class_init(ObjectClass* oc, void* data)
{
DeviceClass* dc = DEVICE_CLASS(oc);
SC14461McuClass* sc14461 = SC14461_MCU_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(oc);
resettable_class_set_parent_phases(rc, NULL, sc14461_reset_hold, NULL, &sc14461->parent_phases);
dc->realize = sc14461_realize;
}
static const TypeInfo sc14461_mcu_types[] = {
{
.name = TYPE_SC14461_MCU,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SC14461McuState),
.class_size = sizeof(SC14461McuClass),
.class_init = sc14461_class_init,
},
};
DEFINE_TYPES(sc14461_mcu_types)

30
hw/cr16c/sc14461.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef HW_SC14461_H
#define HW_SC14461_H
#include "cpu.h"
#include "hw/sysbus.h"
#define TYPE_SC14461_MCU "SC14461"
typedef struct SC14461McuState SC14461McuState;
DECLARE_INSTANCE_CHECKER(SC14461McuState, SC14461_MCU, TYPE_SC14461_MCU)
struct SC14461McuState {
SysBusDevice parent_obj;
CR16CCPU cpu;
MemoryRegion non_shared_ram_or_icache;
MemoryRegion non_shared_ram_or_dcache;
MemoryRegion shared_int_ram;
MemoryRegion boot_rom;
};
typedef struct SC14461McuClass {
SysBusDeviceClass parent_class;
ResettablePhases parent_phases;
} SC14461McuClass;
DECLARE_CLASS_CHECKERS(SC14461McuClass, SC14461_MCU, TYPE_SC14461_MCU)
#endif /* HW_SC14461_H */

63
hw/cr16c/virt.c Normal file
View file

@ -0,0 +1,63 @@
#include "boot.h"
#include "cpu-qom.h"
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "qapi/error.h"
#include "qemu/units.h"
#include "qom/object.h"
typedef struct VirtMachineState {
MachineState parent_obj;
CR16CCPU cpu;
MemoryRegion flash;
} VirtMachineState;
typedef struct VirtMachineClass {
MachineClass parent_class;
} VirtMachineClass;
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
DECLARE_OBJ_CHECKERS(VirtMachineState, VirtMachineClass, VIRT_MACHINE, TYPE_VIRT_MACHINE)
static void virt_init(MachineState* machine)
{
VirtMachineState* m_state = VIRT_MACHINE(machine);
object_initialize_child(OBJECT(machine), "cpu", &m_state->cpu, TYPE_CR16C_CPU);
object_property_set_bool(OBJECT(&m_state->cpu), "realized", true, &error_abort);
memory_region_init_ram(&m_state->flash, NULL, "flash", 16*MiB, &error_fatal);
memory_region_add_subregion(get_system_memory(), 0, &m_state->flash);
if (machine->firmware) {
if (!cr16c_load_firmware(&m_state->cpu, &m_state->flash, machine->firmware)) {
exit(1);
}
}
}
static void virt_class_init(ObjectClass* oc, void* data)
{
MachineClass* mc = MACHINE_CLASS(oc);
mc->desc = "Generic CR16C board for debugging, testing and development";
mc->init = virt_init;
mc->default_cpus = 1;
mc->min_cpus = 1;
mc->max_cpus = 1;
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
mc->is_default = 1;
}
static const TypeInfo virt_machine_types[] = {
{
.name = TYPE_VIRT_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(VirtMachineState),
.class_size = sizeof(VirtMachineClass),
.class_init = virt_class_init,
}
};
DEFINE_TYPES(virt_machine_types);

View file

@ -243,7 +243,6 @@ enum bfd_architecture
#define bfd_mach_rx_v3 0x77
bfd_arch_loongarch,
bfd_arch_cr16c,
#define bfd_mach_sc14450 0x450
bfd_arch_last
};
#define bfd_mach_s390_31 31

View file

@ -84,6 +84,7 @@ blobs = [
'npcm8xx_bootrom.bin',
'vof.bin',
'vof-nvram.bin',
'sc14461-bios.img',
]
dtc = find_program('dtc', required: false)

1
pc-bios/sc14461-bios.img Normal file
View file

@ -0,0 +1 @@
<05><><EFBFBD>

View file

@ -7,7 +7,6 @@
OBJECT_DECLARE_CPU_TYPE(CR16CCPU, CR16CCPUClass, CR16C_CPU)
typedef struct CR16CCPUDef CR16CCPUDef;
struct CR16CCPUClass {
/*< private >*/
CPUClass parent_class;
@ -15,8 +14,6 @@ struct CR16CCPUClass {
/*< public >*/
DeviceRealize parent_realize;
ResettablePhases parent_phases;
CR16CCPUDef* cpu_def;
};
#endif // CR16C_CPU_QOM_H

View file

@ -63,7 +63,7 @@ static void cr16c_cpu_reset_hold(Object *obj, ResetType type)
}
static ObjectClass* cr16c_cpu_class_by_name(const char *cpu_model) {
return object_class_by_name(CR16C_CPU_TYPE_NAME("SC14450C"));
return object_class_by_name(TYPE_CR16C_CPU);
}
static bool cr16c_cpu_has_work(CPUState *cs)
@ -182,55 +182,14 @@ static void cr16c_cpu_class_init(ObjectClass *oc, void *data)
cc->tcg_ops = &cr16c_tcg_ops;
}
static const CR16CCPUDef cr16c_cpu_defs[] = {
static const TypeInfo cr16c_cpu_archs[] = {
{
.name = "SC14450C",
.parent_microarch = TYPE_CR16C_CPU,
}
};
static void cr16c_cpu_cpudef_class_init(ObjectClass *oc, void *data)
{
CR16CCPUClass* acc = CR16C_CPU_CLASS(oc);
acc->cpu_def = data;
}
static char* cr16c_cpu_type_name(const char* model_name)
{
return g_strdup_printf(CR16C_CPU_TYPE_NAME("%s"), model_name);
}
static void cr16c_register_cpudef_type(const struct CR16CCPUDef* def)
{
char* cpu_model_name = cr16c_cpu_type_name(def->name);
TypeInfo ti = {
.name = cpu_model_name,
.parent = def->parent_microarch,
.class_init = cr16c_cpu_cpudef_class_init,
.class_data = (void *)def,
};
type_register_static(&ti);
g_free(cpu_model_name);
}
static const TypeInfo cr16c_cpu_arch = {
.name = TYPE_CR16C_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(CR16CCPU),
.abstract = true,
.class_size = sizeof(CR16CCPUClass),
.class_init = cr16c_cpu_class_init,
},
};
static void cr16c_cpu_register_types(void)
{
int i;
type_register_static(&cr16c_cpu_arch);
for (i = 0; i < ARRAY_SIZE(cr16c_cpu_defs); i++) {
cr16c_register_cpudef_type(&cr16c_cpu_defs[i]);
}
}
type_init(cr16c_cpu_register_types)
DEFINE_TYPES(cr16c_cpu_archs)

View file

@ -8,16 +8,6 @@
#define CR16C_REG_COUNT 14
#define CR16C_FIRST_32B_REG 12
struct CR16CCPUDef {
const char* name;
const char* parent_microarch;
size_t core_type;
size_t series_type;
size_t clock_speed;
};
#define CR16C_CPU_TYPE_SUFFIX "-" TYPE_CR16C_CPU
#define CR16C_CPU_TYPE_NAME(name) (name CR16C_CPU_TYPE_SUFFIX)
#define CPU_RESOLVING_TYPE TYPE_CR16C_CPU
// TODO: Interrupt mask?
@ -47,7 +37,6 @@ struct ArchCPU {
/*< public >*/
CPUCR16CState env;
CPUNegativeOffsetState neg;
};
int cr16c_print_insn(bfd_vma addr, disassemble_info *info);

View file

@ -160,9 +160,9 @@ LSHD_rp 0100 0111 .... .... @shiftd_rp
%br_disp8 56:4 48:4 !function=get_disp8
@br_disp8 .... .... cond:4 .... disp=%br_disp8
BRCOND 0001 .... cond:4 .... disp=%br_disp8
BRCOND_disp8 0001 .... .... .... @br_disp8
JCOND 0000 1010 cond:4 ra:4
EXCP 0000 0000 1100 id:4

View file

@ -1057,11 +1057,8 @@ static bool trans_EXCP(DisasContext *ctx, arg_EXCP *a) {
return true;
}
static bool trans_BRCOND_disp8(DisasContext* ctx, arg_BRCOND_disp8 *a) {
TCGLabel* l = gen_new_label();
static void gen_br_cond(DisasContext* ctx, int cond, TCGLabel* l) {
TCGv temp;
uint32_t pc_this = ctx->base.pc_next - 2;
uint32_t dest = pc_this + a->disp*2;
/* Flags may have higher bits set */
tcg_gen_andi_i32(f_n, f_n, 1);
@ -1070,9 +1067,7 @@ static bool trans_BRCOND_disp8(DisasContext* ctx, arg_BRCOND_disp8 *a) {
tcg_gen_andi_i32(f_l, f_l, 1);
tcg_gen_andi_i32(f_c, f_c, 1);
ctx->base.is_jmp = DISAS_NORETURN;
switch (a->cond) {
switch (cond) {
case CR16C_COND_EQ:
tcg_gen_brcondi_i32(TCG_COND_EQ, f_z, 1, l);
break;
@ -1129,6 +1124,15 @@ static bool trans_BRCOND_disp8(DisasContext* ctx, arg_BRCOND_disp8 *a) {
default:
g_assert_not_reached();
}
}
static bool trans_BRCOND(DisasContext* ctx, arg_BRCOND *a) {
TCGLabel* l = gen_new_label();
gen_br_cond(ctx, a->cond, l);
uint32_t pc_this = ctx->base.pc_next - 2;
uint32_t dest = pc_this + a->disp*2;
gen_goto(&ctx->base, ctx->base.pc_next, 0);
@ -1136,6 +1140,24 @@ static bool trans_BRCOND_disp8(DisasContext* ctx, arg_BRCOND_disp8 *a) {
gen_goto(&ctx->base, dest, 1);
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}
static bool trans_JCOND(DisasContext* ctx, arg_JCOND *a) {
TCGLabel* l = gen_new_label();
gen_br_cond(ctx, a->cond, l);
tcg_gen_movi_i32(pc, ctx->base.pc_next);
tcg_gen_lookup_and_goto_ptr();
gen_set_label(l);
tcg_gen_mov_i32(pc, r[a->ra]);
tcg_gen_lookup_and_goto_ptr();
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}

View file

@ -11,7 +11,7 @@ CR16C_TESTS = $(patsubst $(CR16C_SRC)/%.S, %, $(CR16C_ALL))
TESTS += $(CR16C_TESTS)
VPATH += $(CR16C_SRC)
QEMU_OPTS+=-M sc14450board -nographic $(EXTFLAGS) -bios
QEMU_OPTS+=-M virt -nographic $(EXTFLAGS) -bios
LDFLAGS = -nostdlib -static