提交 525bd324 编写于 作者: A Anthony Green 提交者: Blue Swirl

Add moxie target code

Signed-off-by: NAnthony Green <green@moxielogic.com>
Signed-off-by: NBlue Swirl <blauwirbel@gmail.com>
上级 f7c61bf8
obj-y += translate.o helper.o machine.o cpu.o machine.o
obj-$(CONFIG_SOFTMMU) += mmu.o
/*
* QEMU Moxie CPU
*
* Copyright (c) 2013 Anthony Green
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
#include "qemu-common.h"
#include "migration/vmstate.h"
#include "machine.h"
static void moxie_cpu_reset(CPUState *s)
{
MoxieCPU *cpu = MOXIE_CPU(s);
MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(cpu);
CPUMoxieState *env = &cpu->env;
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", s->cpu_index);
log_cpu_state(env, 0);
}
mcc->parent_reset(s);
memset(env, 0, offsetof(CPUMoxieState, breakpoints));
env->pc = 0x1000;
tlb_flush(env, 1);
}
static void moxie_cpu_realizefn(DeviceState *dev, Error **errp)
{
MoxieCPU *cpu = MOXIE_CPU(dev);
MoxieCPUClass *occ = MOXIE_CPU_GET_CLASS(dev);
qemu_init_vcpu(&cpu->env);
cpu_reset(CPU(cpu));
occ->parent_realize(dev, errp);
}
static void moxie_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
MoxieCPU *cpu = MOXIE_CPU(obj);
static int inited;
cs->env_ptr = &cpu->env;
cpu_exec_init(&cpu->env);
if (tcg_enabled() && !inited) {
inited = 1;
moxie_translate_init();
}
}
static ObjectClass *moxie_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
if (cpu_model == NULL) {
return NULL;
}
oc = object_class_by_name(cpu_model);
if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_MOXIE_CPU) ||
object_class_is_abstract(oc))) {
return NULL;
}
return oc;
}
static void moxie_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
MoxieCPUClass *mcc = MOXIE_CPU_CLASS(oc);
mcc->parent_realize = dc->realize;
dc->realize = moxie_cpu_realizefn;
mcc->parent_reset = cc->reset;
cc->reset = moxie_cpu_reset;
cc->class_by_name = moxie_cpu_class_by_name;
dc->vmsd = &vmstate_moxie_cpu;
}
static void moxielite_initfn(Object *obj)
{
/* Set cpu feature flags */
}
static void moxie_any_initfn(Object *obj)
{
/* Set cpu feature flags */
}
typedef struct MoxieCPUInfo {
const char *name;
void (*initfn)(Object *obj);
} MoxieCPUInfo;
static const MoxieCPUInfo moxie_cpus[] = {
{ .name = "MoxieLite", .initfn = moxielite_initfn },
{ .name = "any", .initfn = moxie_any_initfn },
};
MoxieCPU *cpu_moxie_init(const char *cpu_model)
{
MoxieCPU *cpu;
ObjectClass *oc;
oc = moxie_cpu_class_by_name(cpu_model);
if (oc == NULL) {
return NULL;
}
cpu = MOXIE_CPU(object_new(object_class_get_name(oc)));
cpu->env.cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
return cpu;
}
static void cpu_register(const MoxieCPUInfo *info)
{
TypeInfo type_info = {
.parent = TYPE_MOXIE_CPU,
.instance_size = sizeof(MoxieCPU),
.instance_init = info->initfn,
.class_size = sizeof(MoxieCPUClass),
};
type_info.name = g_strdup_printf("%s-" TYPE_MOXIE_CPU, info->name);
type_register(&type_info);
g_free((void *)type_info.name);
}
static const TypeInfo moxie_cpu_type_info = {
.name = TYPE_MOXIE_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(MoxieCPU),
.instance_init = moxie_cpu_initfn,
.class_size = sizeof(MoxieCPUClass),
.class_init = moxie_cpu_class_init,
};
static void moxie_cpu_register_types(void)
{
int i;
type_register_static(&moxie_cpu_type_info);
for (i = 0; i < ARRAY_SIZE(moxie_cpus); i++) {
cpu_register(&moxie_cpus[i]);
}
}
type_init(moxie_cpu_register_types)
/*
* Moxie emulation
*
* Copyright (c) 2008, 2010, 2013 Anthony Green
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CPU_MOXIE_H
#define _CPU_MOXIE_H
#include "config.h"
#include "qemu-common.h"
#define TARGET_LONG_BITS 32
#define CPUArchState struct CPUMoxieState
#define TARGET_HAS_ICE 1
#define CPU_SAVE_VERSION 1
#define ELF_MACHINE 0xFEED /* EM_MOXIE */
#define MOXIE_EX_DIV0 0
#define MOXIE_EX_BAD 1
#define MOXIE_EX_IRQ 2
#define MOXIE_EX_SWI 3
#define MOXIE_EX_MMU_MISS 4
#define MOXIE_EX_BREAK 16
#include "exec/cpu-defs.h"
#include "fpu/softfloat.h"
#define TARGET_PAGE_BITS 12 /* 4k */
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#define TARGET_VIRT_ADDR_SPACE_BITS 32
#define NB_MMU_MODES 1
typedef struct CPUMoxieState {
uint32_t flags; /* general execution flags */
uint32_t gregs[16]; /* general registers */
uint32_t sregs[256]; /* special registers */
uint32_t pc; /* program counter */
/* Instead of saving the cc value, we save the cmp arguments
and compute cc on demand. */
uint32_t cc_a; /* reg a for condition code calculation */
uint32_t cc_b; /* reg b for condition code calculation */
void *irq[8];
CPU_COMMON
} CPUMoxieState;
#include "qom/cpu.h"
#define TYPE_MOXIE_CPU "moxie-cpu"
#define MOXIE_CPU_CLASS(klass) \
OBJECT_CLASS_CHECK(MoxieCPUClass, (klass), TYPE_MOXIE_CPU)
#define MOXIE_CPU(obj) \
OBJECT_CHECK(MoxieCPU, (obj), TYPE_MOXIE_CPU)
#define MOXIE_CPU_GET_CLASS(obj) \
OBJECT_GET_CLASS(MoxieCPUClass, (obj), TYPE_MOXIE_CPU)
/**
* MoxieCPUClass:
* @parent_reset: The parent class' reset handler.
*
* A Moxie CPU model.
*/
typedef struct MoxieCPUClass {
/*< private >*/
CPUClass parent_class;
/*< public >*/
DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu);
} MoxieCPUClass;
/**
* MoxieCPU:
* @env: #CPUMoxieState
*
* A Moxie CPU.
*/
typedef struct MoxieCPU {
/*< private >*/
CPUState parent_obj;
/*< public >*/
CPUMoxieState env;
} MoxieCPU;
static inline MoxieCPU *moxie_env_get_cpu(CPUMoxieState *env)
{
return MOXIE_CPU(container_of(env, MoxieCPU, env));
}
#define ENV_GET_CPU(e) CPU(moxie_env_get_cpu(e))
#define ENV_OFFSET offsetof(MoxieCPU, env)
MoxieCPU *cpu_moxie_init(const char *cpu_model);
int cpu_moxie_exec(CPUMoxieState *s);
void do_interrupt(CPUMoxieState *env);
void moxie_translate_init(void);
int cpu_moxie_signal_handler(int host_signum, void *pinfo,
void *puc);
static inline CPUMoxieState *cpu_init(const char *cpu_model)
{
MoxieCPU *cpu = cpu_moxie_init(cpu_model);
if (cpu == NULL) {
return NULL;
}
return &cpu->env;
}
#define cpu_exec cpu_moxie_exec
#define cpu_gen_code cpu_moxie_gen_code
#define cpu_signal_handler cpu_moxie_signal_handler
static inline int cpu_mmu_index(CPUMoxieState *env)
{
return 0;
}
#include "exec/cpu-all.h"
#include "exec/exec-all.h"
static inline void cpu_pc_from_tb(CPUMoxieState *env, TranslationBlock *tb)
{
env->pc = tb->pc;
}
static inline void cpu_get_tb_cpu_state(CPUMoxieState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
*pc = env->pc;
*cs_base = 0;
*flags = 0;
}
static inline int cpu_has_work(CPUState *cpu)
{
return cpu->interrupt_request & CPU_INTERRUPT_HARD;
}
int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
int rw, int mmu_idx);
#endif /* _CPU_MOXIE_H */
/*
* Moxie helper routines.
*
* Copyright (c) 2008, 2009, 2010, 2013 Anthony Green
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "config.h"
#include "cpu.h"
#include "mmu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "helper.h"
#define MMUSUFFIX _mmu
#define SHIFT 0
#include "exec/softmmu_template.h"
#define SHIFT 1
#include "exec/softmmu_template.h"
#define SHIFT 2
#include "exec/softmmu_template.h"
#define SHIFT 3
#include "exec/softmmu_template.h"
/* Try to fill the TLB and return an exception if error. If retaddr is
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
void tlb_fill(CPUMoxieState *env, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
int ret;
ret = cpu_moxie_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (unlikely(ret)) {
if (retaddr) {
cpu_restore_state(env, retaddr);
}
}
cpu_loop_exit(env);
}
void helper_raise_exception(CPUMoxieState *env, int ex)
{
env->exception_index = ex;
/* Stash the exception type. */
env->sregs[2] = ex;
/* Stash the address where the exception occurred. */
cpu_restore_state(env, GETPC());
env->sregs[5] = env->pc;
/* Jump the the exception handline routine. */
env->pc = env->sregs[1];
cpu_loop_exit(env);
}
uint32_t helper_div(CPUMoxieState *env, uint32_t a, uint32_t b)
{
if (unlikely(b == 0)) {
helper_raise_exception(env, MOXIE_EX_DIV0);
return 0;
}
if (unlikely(a == INT_MIN && b == -1)) {
return INT_MIN;
}
return (int32_t)a / (int32_t)b;
}
uint32_t helper_udiv(CPUMoxieState *env, uint32_t a, uint32_t b)
{
if (unlikely(b == 0)) {
helper_raise_exception(env, MOXIE_EX_DIV0);
return 0;
}
return a / b;
}
void helper_debug(CPUMoxieState *env)
{
env->exception_index = EXCP_DEBUG;
cpu_loop_exit(env);
}
#if defined(CONFIG_USER_ONLY)
void do_interrupt(CPUState *env)
{
env->exception_index = -1;
}
int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
int rw, int mmu_idx)
{
env->exception_index = 0xaa;
env->debug1 = address;
cpu_dump_state(env, stderr, fprintf, 0);
return 1;
}
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
#else /* !CONFIG_USER_ONLY */
int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
int rw, int mmu_idx)
{
MoxieMMUResult res;
int prot, miss;
target_ulong phy;
int r = 1;
address &= TARGET_PAGE_MASK;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
miss = moxie_mmu_translate(&res, env, address, rw, mmu_idx);
if (miss) {
/* handle the miss. */
phy = 0;
env->exception_index = MOXIE_EX_MMU_MISS;
} else {
phy = res.phy;
r = 0;
}
tlb_set_page(env, address, phy, prot, mmu_idx, TARGET_PAGE_SIZE);
return r;
}
void do_interrupt(CPUMoxieState *env)
{
switch (env->exception_index) {
case MOXIE_EX_BREAK:
break;
default:
break;
}
}
hwaddr cpu_get_phys_page_debug(CPUMoxieState *env, target_ulong addr)
{
uint32_t phy = addr;
MoxieMMUResult res;
int miss;
miss = moxie_mmu_translate(&res, env, addr, 0, 0);
if (!miss) {
phy = res.phy;
}
return phy;
}
#endif
#include "exec/def-helper.h"
DEF_HELPER_2(raise_exception, void, env, int)
DEF_HELPER_1(debug, void, env)
DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i32, env, i32, i32)
#include "exec/def-helper.h"
#include "hw/hw.h"
#include "hw/boards.h"
const VMStateDescription vmstate_moxie_cpu = {
.name = "cpu",
.version_id = CPU_SAVE_VERSION,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(flags, CPUMoxieState),
VMSTATE_UINT32_ARRAY(gregs, CPUMoxieState, 16),
VMSTATE_UINT32_ARRAY(sregs, CPUMoxieState, 256),
VMSTATE_UINT32(pc, CPUMoxieState),
VMSTATE_UINT32(cc_a, CPUMoxieState),
VMSTATE_UINT32(cc_b, CPUMoxieState),
VMSTATE_END_OF_LIST()
}
};
void cpu_save(QEMUFile *f, void *opaque)
{
vmstate_save_state(f, &vmstate_moxie_cpu, opaque);
}
int cpu_load(QEMUFile *f, void *opaque, int version_id)
{
return vmstate_load_state(f, &vmstate_moxie_cpu, opaque, version_id);
}
extern const VMStateDescription vmstate_moxie_cpu;
/*
* Moxie mmu emulation.
*
* Copyright (c) 2008, 2013 Anthony Green
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "config.h"
#include "cpu.h"
#include "mmu.h"
#include "exec/exec-all.h"
int moxie_mmu_translate(MoxieMMUResult *res,
CPUMoxieState *env, uint32_t vaddr,
int rw, int mmu_idx)
{
/* Perform no translation yet. */
res->phy = vaddr;
return 0;
}
#define MOXIE_MMU_ERR_EXEC 0
#define MOXIE_MMU_ERR_READ 1
#define MOXIE_MMU_ERR_WRITE 2
#define MOXIE_MMU_ERR_FLUSH 3
typedef struct {
uint32_t phy;
uint32_t pfn;
int g:1;
int v:1;
int k:1;
int w:1;
int e:1;
int cause_op;
} MoxieMMUResult;
int moxie_mmu_translate(MoxieMMUResult *res,
CPUMoxieState *env, uint32_t vaddr,
int rw, int mmu_idx);
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册