qemu-cr16/target/cr16c/cpu.c
2026-05-04 14:31:19 +02:00

227 lines
6.4 KiB
C

#include "qemu/osdep.h"
#include "exec/cputlb.h"
#include "accel/tcg/cpu-ops.h"
#include "hw/resettable.h"
#include "qemu/qemu-print.h"
#include "qemu/typedefs.h"
#include "qom/object.h"
#include "qapi/error.h"
#include "cpu.h"
#include "disas/dis-asm.h"
#include "exec/cpu-interrupt.h"
#include "exec/target_page.h"
static void cr16c_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) {
info->mach = bfd_arch_cr16c;
info->endian = BFD_ENDIAN_LITTLE;
info->print_insn = cr16c_print_insn;
}
static void cr16c_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState* cs = CPU(dev);
CR16CCPUClass* ccc = CR16C_CPU_GET_CLASS(dev);
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
qemu_init_vcpu(cs);
cpu_reset(cs);
ccc->parent_realize(dev, errp);
}
static void cr16c_cpu_reset_hold(Object *obj, ResetType type)
{
CPUState *cs = CPU(obj);
CR16CCPU *cpu = CR16C_CPU(cs);
CR16CCPUClass *ccc = CR16C_CPU_GET_CLASS(obj);
CPUCR16CState* env = &cpu->env;
// TODO: Interrupts
if (ccc->parent_phases.hold) {
ccc->parent_phases.hold(obj, type);
}
for(int i = 0; i < CR16C_REG_COUNT; i++) {
env->r[i] = 0;
}
env->r[0] = env->pc;
env->r[1] = env->pc >> 16;
env->psr_n = 0;
env->psr_z = 0;
env->psr_f = 0;
env->psr_l = 0;
env->psr_c = 0;
env->psr_t = 0;
env->psr_u = 0;
env->psr_e = 0;
env->psr_p = 0;
env->psr_i = 0;
env->pc = 0;
}
static ObjectClass* cr16c_cpu_class_by_name(const char *cpu_model) {
return object_class_by_name(TYPE_CR16C_CPU);
}
static bool cr16c_cpu_has_work(CPUState *cs)
{
CR16CCPU *cpu = CR16C_CPU(cs);
CPUCR16CState *env = &cpu->env;
return (cs->interrupt_request & CPU_INTERRUPT_HARD) && cpu_interrupts_enabled(env);
}
static void cr16c_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
CPUCR16CState* env = cpu_env(cs);
qemu_fprintf(f, "-- Special purpose registers --\n");
qemu_fprintf(f, "PC: " TARGET_FMT_lx "\n", env->pc);
qemu_fprintf(f, "-- General purpose registers --\n");
for(int i = 0; i < 10; i++) {
qemu_fprintf(f, "R%d: %04x\n", i, env->r[i]);
}
for(int i = 10; i < CR16C_FIRST_32B_REG; i++) {
qemu_fprintf(f, "R%d: %04x\n", i, env->r[i]);
}
for(int i = CR16C_FIRST_32B_REG; i < CR16C_REG_COUNT - 2; i++) {
qemu_fprintf(f, "R%d: %08x\n", i, env->r[i]);
}
qemu_fprintf(f, "RA: " TARGET_FMT_lx "\n", env->r[CR16C_REGNO_RA]);
qemu_fprintf(f, "SP: " TARGET_FMT_lx "\n", env->r[CR16C_REGNO_SP]);
qemu_fprintf(f, "-- Flags --\n");
qemu_fprintf(f, "PSR: %04x\n", cr16c_cpu_pack_psr(env));
qemu_fprintf(f, ". I P E N Z F U L T C\n");
qemu_fprintf(f, ". %d %d %d %d %d %d %d %d %d %d\n",
env->psr_i, env->psr_p, env->psr_e, env->psr_n, env->psr_z, env->psr_f, env->psr_u, env->psr_l, env->psr_t, env->psr_c);
qemu_fprintf(f, "CFG: %04x\n", cr16c_cpu_pack_cfg(env));
qemu_fprintf(f, ". SR ED LIC IC DC\n");
qemu_fprintf(f, ". %d %d %d %d %d\n",
env->cfg_sr, env->cfg_ed, env->cfg_lic, env->cfg_ic, env->cfg_dc);
qemu_fprintf(f, "\n");
}
/* For debugging only, until tracing and exceptions are implemented */
void cr16c_debug_dump_state(CPUState *cs) {
cr16c_cpu_dump_state(cs, stdout, 0);
}
static void cr16c_cpu_set_pc(CPUState *cs, vaddr value)
{
CR16CCPU *cpu = CR16C_CPU(cs);
cpu->env.pc = value;
}
static vaddr cr16c_cpu_get_pc(CPUState *cs)
{
CR16CCPU *cpu = CR16C_CPU(cs);
return cpu->env.pc;
}
static int cr16c_cpu_mmu_index(CPUState *cs, bool ifetch)
{
return 0;
}
static bool cr16c_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
// TODO
return false;
}
hwaddr cr16c_cpu_get_phys_page_debug(CPUState* cs, vaddr addr) {
return addr;
}
static TCGTBCPUState cr16c_cpu_get_tb_cpu_state(CPUState *cs) {
CPUCR16CState *env = cpu_env(cs);
return (TCGTBCPUState){ .pc = env->pc };
}
bool cr16c_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
{
/* Copied from rx */
uint32_t address, physical, prot;
/* Linear mapping */
address = physical = addr & TARGET_PAGE_MASK;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
tlb_set_page(cs, address, physical, prot, mmu_idx, TARGET_PAGE_SIZE);
return true;
}
void cr16c_restore_state_to_opc(CPUState *cpu, const TranslationBlock *tb,
const uint64_t *data) {
qemu_printf("idk what im doing!!!!!!\n");
// TODO figure out what this is supposed to do and implement it
}
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps cr16c_sysemu_ops = {
.get_phys_page_debug = cr16c_cpu_get_phys_page_debug,
.has_work = cr16c_cpu_has_work,
};
static const struct TCGCPUOps cr16c_tcg_ops = {
.initialize = cr16c_translate_init,
.mmu_index = cr16c_cpu_mmu_index,
.cpu_exec_interrupt = cr16c_cpu_exec_interrupt,
.cpu_exec_reset = cpu_reset,
.translate_code = cr16c_translate_code,
.get_tb_cpu_state = cr16c_cpu_get_tb_cpu_state,
.restore_state_to_opc = cr16c_restore_state_to_opc,
.tlb_fill = cr16c_cpu_tlb_fill,
.pointer_wrap = cpu_pointer_wrap_notreached,
.cpu_exec_halt = cr16c_cpu_has_work,
};
static void cr16c_cpu_class_init(ObjectClass *oc, const void *data)
{
CR16CCPUClass *acc = CR16C_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
ResettableClass *rc = RESETTABLE_CLASS(cc);
device_class_set_parent_realize(dc, cr16c_cpu_realizefn, &acc->parent_realize);
resettable_class_set_parent_phases(rc, NULL, cr16c_cpu_reset_hold, NULL, &acc->parent_phases);
cc->class_by_name = cr16c_cpu_class_by_name;
cc->dump_state = cr16c_cpu_dump_state;
cc->set_pc = cr16c_cpu_set_pc;
cc->get_pc = cr16c_cpu_get_pc;
cc->sysemu_ops = &cr16c_sysemu_ops;
cc->disas_set_info = cr16c_cpu_disas_set_info;
cc->tcg_ops = &cr16c_tcg_ops;
}
static const TypeInfo cr16c_cpu_archs[] = {
{
.name = TYPE_CR16C_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(CR16CCPU),
.class_size = sizeof(CR16CCPUClass),
.class_init = cr16c_cpu_class_init,
},
};
DEFINE_TYPES(cr16c_cpu_archs)