226 lines
6.3 KiB
C
226 lines
6.3 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) {
|
|
cpu_env(cpu)->pc = data[0];
|
|
}
|
|
|
|
|
|
#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)
|