* [Qemu-devel] [PATCH v7 0/4] Moxie CPU port @ 2013-03-03 13:07 Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 1/4] Add moxie target code Anthony Green ` (3 more replies) 0 siblings, 4 replies; 8+ messages in thread From: Anthony Green @ 2013-03-03 13:07 UTC (permalink / raw) To: qemu-devel; +Cc: Anthony Green This version consolidates the helper file (helper.c & op_helper.c) and addresses the signed division of INT_MIN by -1 issue (which is now == 0x8000000). Hopefully this is looking much better to everybody now. Thanks! AG Anthony Green (4): Add moxie target code Add moxie disassembler Add sample moxie system Add top level changes for moxie MAINTAINERS | 5 + arch_init.c | 2 + configure | 9 +- cpu-exec.c | 2 + default-configs/moxie-softmmu.mak | 2 + disas.c | 6 + disas/Makefile.objs | 1 + disas/moxie.c | 360 +++++++++++++ hw/moxie/Makefile.objs | 6 + hw/moxie/moxiesim.c | 174 +++++++ include/disas/bfd.h | 66 +-- include/sysemu/arch_init.h | 1 + qapi-schema.json | 6 +- target-moxie/Makefile.objs | 2 + target-moxie/cpu.c | 172 +++++++ target-moxie/cpu.h | 170 +++++++ target-moxie/helper.c | 170 +++++++ target-moxie/helper.h | 9 + target-moxie/machine.c | 27 + target-moxie/machine.h | 2 + target-moxie/mmu.c | 36 ++ target-moxie/mmu.h | 19 + target-moxie/translate.c | 1003 +++++++++++++++++++++++++++++++++++++ 23 files changed, 2214 insertions(+), 36 deletions(-) create mode 100644 default-configs/moxie-softmmu.mak create mode 100644 disas/moxie.c create mode 100644 hw/moxie/Makefile.objs create mode 100644 hw/moxie/moxiesim.c create mode 100644 target-moxie/Makefile.objs create mode 100644 target-moxie/cpu.c create mode 100644 target-moxie/cpu.h create mode 100644 target-moxie/helper.c create mode 100644 target-moxie/helper.h create mode 100644 target-moxie/machine.c create mode 100644 target-moxie/machine.h create mode 100644 target-moxie/mmu.c create mode 100644 target-moxie/mmu.h create mode 100644 target-moxie/translate.c -- 1.8.1.4 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v7 1/4] Add moxie target code 2013-03-03 13:07 [Qemu-devel] [PATCH v7 0/4] Moxie CPU port Anthony Green @ 2013-03-03 13:07 ` Anthony Green 2013-03-03 16:15 ` Blue Swirl 2013-03-03 22:09 ` Peter Maydell 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 2/4] Add moxie disassembler Anthony Green ` (2 subsequent siblings) 3 siblings, 2 replies; 8+ messages in thread From: Anthony Green @ 2013-03-03 13:07 UTC (permalink / raw) To: qemu-devel; +Cc: Anthony Green Signed-off-by: Anthony Green <green@moxielogic.com> --- target-moxie/Makefile.objs | 2 + target-moxie/cpu.c | 172 ++++++++ target-moxie/cpu.h | 170 ++++++++ target-moxie/helper.c | 170 ++++++++ target-moxie/helper.h | 9 + target-moxie/machine.c | 27 ++ target-moxie/machine.h | 2 + target-moxie/mmu.c | 36 ++ target-moxie/mmu.h | 19 + target-moxie/translate.c | 1003 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1610 insertions(+) create mode 100644 target-moxie/Makefile.objs create mode 100644 target-moxie/cpu.c create mode 100644 target-moxie/cpu.h create mode 100644 target-moxie/helper.c create mode 100644 target-moxie/helper.h create mode 100644 target-moxie/machine.c create mode 100644 target-moxie/machine.h create mode 100644 target-moxie/mmu.c create mode 100644 target-moxie/mmu.h create mode 100644 target-moxie/translate.c diff --git a/target-moxie/Makefile.objs b/target-moxie/Makefile.objs new file mode 100644 index 0000000..6381d4d --- /dev/null +++ b/target-moxie/Makefile.objs @@ -0,0 +1,2 @@ +obj-y += translate.o helper.o machine.o cpu.o machine.o +obj-$(CONFIG_SOFTMMU) += mmu.o diff --git a/target-moxie/cpu.c b/target-moxie/cpu.c new file mode 100644 index 0000000..c17d3f0 --- /dev/null +++ b/target-moxie/cpu.c @@ -0,0 +1,172 @@ +/* + * 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) diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h new file mode 100644 index 0000000..eb7354f --- /dev/null +++ b/target-moxie/cpu.h @@ -0,0 +1,170 @@ +/* + * 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 + +#define CC_GT (1<<0) +#define CC_LT (1<<1) +#define CC_EQ (1<<2) +#define CC_GTU (1<<3) +#define CC_LTU (1<<4) + +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 */ + uint32_t cc; /* condition codes */ + + 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)) + +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) +{ + CPUMoxieState *env = &MOXIE_CPU(cpu)->env; + + return env->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 */ diff --git a/target-moxie/helper.c b/target-moxie/helper.c new file mode 100644 index 0000000..6de0598 --- /dev/null +++ b/target-moxie/helper.c @@ -0,0 +1,170 @@ +/* + * 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, uint32_t pc, int ex) +{ + env->exception_index = ex; + /* Stash the exception type. */ + env->sregs[2] = ex; + /* Stash the address where the exception occurred. */ + env->sregs[5] = pc; + /* Jump the the exception handline routine. */ + env->pc = env->sregs[1]; + cpu_loop_exit(env); +} + +uint32_t helper_div(CPUMoxieState *env, uint32_t pc, uint32_t a, uint32_t b) +{ + if (unlikely(b == 0)) { + helper_raise_exception(env, pc, 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 pc, uint32_t a, uint32_t b) +{ + if (unlikely(b == 0)) { + helper_raise_exception(env, pc, 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) +{ + struct moxie_mmu_result_t 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; + struct moxie_mmu_result_t res; + int miss; + miss = moxie_mmu_translate(&res, env, addr, 0, 0); + if (!miss) { + phy = res.phy; + } + return phy; +} +#endif diff --git a/target-moxie/helper.h b/target-moxie/helper.h new file mode 100644 index 0000000..36ce126 --- /dev/null +++ b/target-moxie/helper.h @@ -0,0 +1,9 @@ +#include "exec/def-helper.h" + +DEF_HELPER_3(raise_exception, void, env, i32, int) +DEF_HELPER_1(debug, void, env) +DEF_HELPER_4(div, i32, env, i32, i32, i32) +DEF_HELPER_4(udiv, i32, env, i32, i32, i32) + +#include "exec/def-helper.h" + diff --git a/target-moxie/machine.c b/target-moxie/machine.c new file mode 100644 index 0000000..b8ed253 --- /dev/null +++ b/target-moxie/machine.c @@ -0,0 +1,27 @@ +#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, 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); +} diff --git a/target-moxie/machine.h b/target-moxie/machine.h new file mode 100644 index 0000000..eeb1b73 --- /dev/null +++ b/target-moxie/machine.h @@ -0,0 +1,2 @@ +extern const VMStateDescription vmstate_moxie_cpu; + diff --git a/target-moxie/mmu.c b/target-moxie/mmu.c new file mode 100644 index 0000000..5217eed --- /dev/null +++ b/target-moxie/mmu.c @@ -0,0 +1,36 @@ +/* + * 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; +} diff --git a/target-moxie/mmu.h b/target-moxie/mmu.h new file mode 100644 index 0000000..25a7609 --- /dev/null +++ b/target-moxie/mmu.h @@ -0,0 +1,19 @@ +#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 moxie_mmu_result_t { + 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); diff --git a/target-moxie/translate.c b/target-moxie/translate.c new file mode 100644 index 0000000..7ed4c0b --- /dev/null +++ b/target-moxie/translate.c @@ -0,0 +1,1003 @@ +/* + * Moxie emulation for qemu: main translation routines. + * + * Copyright (c) 2009, 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/>. + */ + +/* For information on the Moxie architecture, see + * http://moxielogic.org/wiki + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <assert.h> + +#include "cpu.h" +#include "exec/exec-all.h" +#include "disas/disas.h" +#include "tcg-op.h" + +#include "helper.h" +#define GEN_HELPER 1 +#include "helper.h" + +/* This is the state at translation time. */ +typedef struct DisasContext { + struct TranslationBlock *tb; + target_ulong pc, saved_pc; + uint32_t opcode; + uint32_t fp_status; + /* Routine used to access memory */ + int memidx; + int bstate; + target_ulong btarget; + int singlestep_enabled; +} DisasContext; + +enum { + BS_NONE = 0, /* We go out of the TB without reaching a branch or an + * exception condition */ + BS_STOP = 1, /* We want to stop translation for any reason */ + BS_BRANCH = 2, /* We reached a branch condition */ + BS_EXCP = 3, /* We reached an exception condition */ +}; + +static TCGv cpu_pc; +static TCGv cpu_gregs[16]; +static TCGv_ptr cpu_env; +static TCGv cc; + +#define REG(x) (cpu_gregs[x]) + +/* Extract the signed 10-bit offset from a 16-bit branch + instruction. */ +#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1) + +void cpu_dump_state(CPUArchState *env, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + int i; + cpu_fprintf(f, "pc=0x%08x\n", env->pc); + cpu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n", + env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]); + for (i = 4; i < 16; i += 4) { + cpu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n", + i-2, env->gregs[i], i-1, env->gregs[i + 1], + i, env->gregs[i + 2], i+1, env->gregs[i + 3]); + } + cpu_fprintf(f, "sr0=0x%08x $r1=0x%08x\n", + env->sregs[0], env->sregs[1]); +} + +void moxie_translate_init(void) +{ + int i; + static int done_init; + static const char * const gregnames[16] = { + "$fp", "$sp", "$r0", "$r1", + "$r2", "$r3", "$r4", "$r5", + "$r6", "$r7", "$r8", "$r9", + "$r10", "$r11", "$r12", "$r13" + }; + + if (done_init) { + return; + } + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + cpu_pc = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUMoxieState, pc), "$pc"); + for (i = 0; i < 24; i++) + cpu_gregs[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUMoxieState, gregs[i]), + gregnames[i]); + + cc = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUMoxieState, cc), "cc"); + + done_init = 1; +} + +static inline void gen_goto_tb(CPUMoxieState *env, DisasContext *ctx, + int n, target_ulong dest) +{ + TranslationBlock *tb; + tb = ctx->tb; + + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && + !ctx->singlestep_enabled) { + tcg_gen_goto_tb(n); + tcg_gen_movi_i32(cpu_pc, dest); + tcg_gen_exit_tb((long) tb + n); + } else { + tcg_gen_movi_i32(cpu_pc, dest); + if (ctx->singlestep_enabled) { + gen_helper_debug(cpu_env); + } + tcg_gen_exit_tb(0); + } +} + +static int decode_opc(MoxieCPU *cpu, DisasContext *ctx) +{ + CPUMoxieState *env = &cpu->env; + + /* Local cache for the instruction opcode. */ + int opcode; + /* Set the default instruction length. */ + int length = 2; + + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { + tcg_gen_debug_insn_start(ctx->pc); + } + + /* Examine the 16-bit opcode. */ + opcode = ctx->opcode; + + /* Decode instruction. */ + if (opcode & (1 << 15)) { + if (opcode & (1 << 14)) { + /* This is a Form 3 instruction. */ + int inst = (opcode >> 10 & 0xf); + + switch (inst) { + case 0x00: /* beq */ + { + int l1 = gen_new_label(); + tcg_gen_brcondi_i32(TCG_COND_EQ, cc, CC_EQ, l1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x01: /* bne */ + { + int l1 = gen_new_label(); + tcg_gen_brcondi_i32(TCG_COND_NE, cc, CC_EQ, l1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x02: /* blt */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_LT); + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_LT, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x03: /* bgt */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_GT); + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_GT, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x04: /* bltu */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_LTU); + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_LTU, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x05: /* bgtu */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_GTU); + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_GTU, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x06: /* bge */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_GT|CC_EQ); + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x07: /* ble */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_LT|CC_EQ); + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x08: /* bgeu */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_GTU|CC_EQ); + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + case 0x09: /* bleu */ + { + int l1 = gen_new_label(); + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t1, cc, CC_LTU|CC_EQ); + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); + tcg_temp_free_i32(t1); + gen_goto_tb(env, ctx, 1, ctx->pc + 2); + gen_set_label(l1); + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); + ctx->bstate = BS_BRANCH; + } + break; + default: + { + TCGv temp = tcg_temp_new_i32(); + tcg_gen_movi_i32(cpu_pc, ctx->pc); + tcg_gen_movi_i32(temp, MOXIE_EX_BAD); + gen_helper_raise_exception(cpu_env, cpu_pc, temp); + tcg_temp_free_i32(temp); + } + break; + } + } else { + /* This is a Form 2 instruction. */ + int inst = (opcode >> 12 & 0x3); + switch (inst) { + case 0x00: /* inc */ + { + int a = (opcode >> 8) & 0xf; + unsigned int v = (opcode & 0xff); + tcg_gen_addi_i32(REG(a), REG(a), v); + } + break; + case 0x01: /* dec */ + { + int a = (opcode >> 8) & 0xf; + unsigned int v = (opcode & 0xff); + tcg_gen_subi_i32(REG(a), REG(a), v); + } + break; + case 0x02: /* gsr */ + { + int a = (opcode >> 8) & 0xf; + unsigned v = (opcode & 0xff); + tcg_gen_ld_i32(REG(a), cpu_env, + offsetof(CPUMoxieState, sregs[v])); + } + break; + case 0x03: /* ssr */ + { + int a = (opcode >> 8) & 0xf; + unsigned v = (opcode & 0xff); + tcg_gen_st_i32(REG(a), cpu_env, + offsetof(CPUMoxieState, sregs[v])); + } + break; + default: + { + TCGv temp = tcg_temp_new_i32(); + tcg_gen_movi_i32(cpu_pc, ctx->pc); + tcg_gen_movi_i32(temp, MOXIE_EX_BAD); + gen_helper_raise_exception(cpu_env, cpu_pc, temp); + tcg_temp_free_i32(temp); + } + break; + } + } + } else { + /* This is a Form 1 instruction. */ + int inst = opcode >> 8; + switch (inst) { + case 0x00: /* nop */ + break; + case 0x01: /* ldi.l (immediate) */ + { + int reg = (opcode >> 4) & 0xf; + int val = cpu_ldl_code(env, ctx->pc + 2); + tcg_gen_movi_i32(REG(reg), val); + length = 6; + } + break; + case 0x02: /* mov (register-to-register) */ + { + int dest = (opcode >> 4) & 0xf; + int src = opcode & 0xf; + tcg_gen_mov_i32(REG(dest), REG(src)); + } + break; + case 0x03: /* jsra */ + { + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + tcg_gen_movi_i32(t1, ctx->pc + 6); + + /* Make space for the static chain and return address. */ + tcg_gen_subi_i32(t2, REG(1), 8); + tcg_gen_mov_i32(REG(1), t2); + tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); + + /* Push the current frame pointer. */ + tcg_gen_subi_i32(t2, REG(1), 4); + tcg_gen_mov_i32(REG(1), t2); + tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); + + /* Set the pc and $fp. */ + tcg_gen_mov_i32(REG(0), REG(1)); + + gen_goto_tb(env, ctx, 0, cpu_ldl_code(env, ctx->pc + 2)); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + ctx->bstate = BS_BRANCH; + length = 6; + } + break; + case 0x04: /* ret */ + { + TCGv t1 = tcg_temp_new_i32(); + + /* The new $sp is the old $fp. */ + tcg_gen_mov_i32(REG(1), REG(0)); + + /* Pop the frame pointer. */ + tcg_gen_qemu_ld32u(REG(0), REG(1), ctx->memidx); + tcg_gen_addi_i32(t1, REG(1), 4); + tcg_gen_mov_i32(REG(1), t1); + + + /* Pop the return address and skip over the static chain + slot. */ + tcg_gen_qemu_ld32u(cpu_pc, REG(1), ctx->memidx); + tcg_gen_addi_i32(t1, REG(1), 8); + tcg_gen_mov_i32(REG(1), t1); + + tcg_temp_free_i32(t1); + + /* Jump... */ + tcg_gen_exit_tb(0); + + ctx->bstate = BS_BRANCH; + } + break; + case 0x05: /* add.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_add_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x06: /* push */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + TCGv t1 = tcg_temp_new_i32(); + tcg_gen_subi_i32(t1, REG(a), 4); + tcg_gen_mov_i32(REG(a), t1); + tcg_gen_qemu_st32(REG(b), REG(a), ctx->memidx); + tcg_temp_free_i32(t1); + } + break; + case 0x07: /* pop */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_qemu_ld32u(REG(b), REG(a), ctx->memidx); + tcg_gen_addi_i32(t1, REG(a), 4); + tcg_gen_mov_i32(REG(a), t1); + tcg_temp_free_i32(t1); + } + break; + case 0x08: /* lda.l */ + { + int reg = (opcode >> 4) & 0xf; + + TCGv ptr = tcg_temp_new_i32(); + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_ld32u(REG(reg), ptr, ctx->memidx); + tcg_temp_free_i32(ptr); + + length = 6; + } + break; + case 0x09: /* sta.l */ + { + int val = (opcode >> 4) & 0xf; + + TCGv ptr = tcg_temp_new_i32(); + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_st32(REG(val), ptr, ctx->memidx); + tcg_temp_free_i32(ptr); + + length = 6; + } + break; + case 0x0a: /* ld.l (register indirect) */ + { + int src = opcode & 0xf; + int dest = (opcode >> 4) & 0xf; + + tcg_gen_qemu_ld32u(REG(dest), REG(src), ctx->memidx); + } + break; + case 0x0b: /* st.l */ + { + int dest = (opcode >> 4) & 0xf; + int val = opcode & 0xf; + + tcg_gen_qemu_st32(REG(val), REG(dest), ctx->memidx); + } + break; + case 0x0c: /* ldo.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_ld32u(t2, t1, ctx->memidx); + tcg_gen_mov_i32(REG(a), t2); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + length = 6; + } + break; + case 0x0d: /* sto.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_st32(REG(b), t1, ctx->memidx); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + length = 6; + } + break; + case 0x0e: /* cmp */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + int label_equal = gen_new_label(); + int label_done = gen_new_label(); + + /* Clear CC */ + tcg_gen_movi_i32(cc, 0); + + tcg_gen_brcond_i32(TCG_COND_EQ, REG(a), REG(b), label_equal); + +#define CMPTEST(t, CODE) \ + { \ + int lyes = gen_new_label(); \ + int lno = gen_new_label(); \ + tcg_gen_brcond_i32(t, REG(a), REG(b), lyes); \ + tcg_gen_br(lno); \ + gen_set_label(lyes); \ + tcg_gen_ori_i32(cc, cc, CODE); \ + gen_set_label(lno); \ + } + CMPTEST(TCG_COND_LT, CC_LT); + CMPTEST(TCG_COND_GT, CC_GT); + CMPTEST(TCG_COND_LTU, CC_LTU); + CMPTEST(TCG_COND_GTU, CC_GTU); + tcg_gen_br(label_done); + gen_set_label(label_equal); + tcg_gen_movi_i32(cc, CC_EQ); + gen_set_label(label_done); + } + break; + case 0x19: /* jsr */ + { + int fnreg = (opcode >> 4) & 0xf; + + /* Load the stack pointer into T0. */ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + tcg_gen_movi_i32(t1, ctx->pc + 2); + + /* Make space for the static chain and return address. */ + tcg_gen_subi_i32(t2, REG(1), 8); + tcg_gen_mov_i32(REG(1), t2); + tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); + + /* Push the current frame pointer. */ + tcg_gen_subi_i32(t2, REG(1), 4); + tcg_gen_mov_i32(REG(1), t2); + tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); + + /* Set the pc and $fp. */ + tcg_gen_mov_i32(REG(0), REG(1)); + tcg_gen_mov_i32(cpu_pc, REG(fnreg)); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_gen_exit_tb(0); + ctx->bstate = BS_BRANCH; + } + break; + case 0x1a: /* jmpa */ + { + tcg_gen_movi_i32(cpu_pc, cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_exit_tb(0); + ctx->bstate = BS_BRANCH; + length = 6; + } + break; + case 0x1b: /* ldi.b (immediate) */ + { + int reg = (opcode >> 4) & 0xf; + int val = cpu_ldl_code(env, ctx->pc + 2); + tcg_gen_movi_i32(REG(reg), val); + length = 6; + } + break; + case 0x1c: /* ld.b (register indirect) */ + { + int src = opcode & 0xf; + int dest = (opcode >> 4) & 0xf; + + tcg_gen_qemu_ld8u(REG(dest), REG(src), ctx->memidx); + } + break; + case 0x1d: /* lda.b */ + { + int reg = (opcode >> 4) & 0xf; + + TCGv ptr = tcg_temp_new_i32(); + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_ld8u(REG(reg), ptr, ctx->memidx); + tcg_temp_free_i32(ptr); + + length = 6; + } + break; + case 0x1e: /* st.b */ + { + int dest = (opcode >> 4) & 0xf; + int val = opcode & 0xf; + + tcg_gen_qemu_st8(REG(val), REG(dest), ctx->memidx); + } + break; + case 0x1f: /* sta.b */ + { + int val = (opcode >> 4) & 0xf; + + TCGv ptr = tcg_temp_new_i32(); + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_st8(REG(val), ptr, ctx->memidx); + tcg_temp_free_i32(ptr); + + length = 6; + } + break; + case 0x20: /* ldi.s (immediate) */ + { + int reg = (opcode >> 4) & 0xf; + int val = cpu_ldl_code(env, ctx->pc + 2); + tcg_gen_movi_i32(REG(reg), val); + length = 6; + } + break; + case 0x21: /* ld.s (register indirect) */ + { + int src = opcode & 0xf; + int dest = (opcode >> 4) & 0xf; + + tcg_gen_qemu_ld16u(REG(dest), REG(src), ctx->memidx); + } + break; + case 0x22: /* lda.s */ + { + int reg = (opcode >> 4) & 0xf; + + TCGv ptr = tcg_temp_new_i32(); + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_ld16u(REG(reg), ptr, ctx->memidx); + tcg_temp_free_i32(ptr); + + length = 6; + } + break; + case 0x23: /* st.s */ + { + int dest = (opcode >> 4) & 0xf; + int val = opcode & 0xf; + + tcg_gen_qemu_st16(REG(val), REG(dest), ctx->memidx); + } + break; + case 0x24: /* sta.s */ + { + int val = (opcode >> 4) & 0xf; + + TCGv ptr = tcg_temp_new_i32(); + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_st16(REG(val), ptr, ctx->memidx); + tcg_temp_free_i32(ptr); + + length = 6; + } + break; + case 0x25: /* jmp */ + { + int reg = (opcode >> 4) & 0xf; + tcg_gen_mov_i32(cpu_pc, REG(reg)); + tcg_gen_exit_tb(0); + ctx->bstate = BS_BRANCH; + } + break; + case 0x26: /* and */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_and_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x27: /* lshr */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_shr_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x28: /* ashl */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_shl_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x29: /* sub.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_sub_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x2a: /* neg */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_neg_i32(REG(a), REG(b)); + } + break; + case 0x2b: /* or */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_or_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x2c: /* not */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_not_i32(REG(a), REG(b)); + } + break; + case 0x2d: /* ashr */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_sar_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x2e: /* xor */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_xor_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x2f: /* mul.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + tcg_gen_mul_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x30: /* swi */ + { + int val = cpu_ldl_code(env, ctx->pc + 2); + + TCGv temp = tcg_temp_new_i32(); + tcg_gen_movi_i32(temp, val); + tcg_gen_st_i32(temp, cpu_env, + offsetof(CPUMoxieState, sregs[3])); + tcg_gen_movi_i32(cpu_pc, ctx->pc); + tcg_gen_movi_i32(temp, MOXIE_EX_SWI); + gen_helper_raise_exception(cpu_env, cpu_pc, temp); + tcg_temp_free_i32(temp); + + length = 6; + } + break; + case 0x31: /* div.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + tcg_gen_movi_i32(cpu_pc, ctx->pc); + gen_helper_div(REG(a), cpu_env, cpu_pc, REG(a), REG(b)); + } + break; + case 0x32: /* udiv.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + tcg_gen_movi_i32(cpu_pc, ctx->pc); + gen_helper_udiv(REG(a), cpu_env, cpu_pc, REG(a), REG(b)); + } + break; + case 0x33: /* mod.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + tcg_gen_rem_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x34: /* umod.l */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + tcg_gen_remu_i32(REG(a), REG(a), REG(b)); + } + break; + case 0x35: /* brk */ + { + gen_helper_debug(cpu_env); + } + break; + case 0x36: /* ldo.b */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_ld8u(t2, t1, ctx->memidx); + tcg_gen_mov_i32(REG(a), t2); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + length = 6; + } + break; + case 0x37: /* sto.b */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_st8(REG(b), t1, ctx->memidx); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + length = 6; + } + break; + case 0x38: /* ldo.s */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_ld16u(t2, t1, ctx->memidx); + tcg_gen_mov_i32(REG(a), t2); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + length = 6; + } + break; + case 0x39: /* sto.s */ + { + int a = (opcode >> 4) & 0xf; + int b = opcode & 0xf; + + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc + 2)); + tcg_gen_qemu_st16(REG(b), t1, ctx->memidx); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + + length = 6; + } + break; + default: + { + TCGv temp = tcg_temp_new_i32(); + tcg_gen_movi_i32(cpu_pc, ctx->pc); + tcg_gen_movi_i32(temp, MOXIE_EX_BAD); + gen_helper_raise_exception(cpu_env, cpu_pc, temp); + tcg_temp_free_i32(temp); + } + break; + } + } + + return length; +} + +/* generate intermediate code for basic block 'tb'. */ +static void +gen_intermediate_code_internal(MoxieCPU *cpu, TranslationBlock *tb, + bool search_pc) +{ + DisasContext ctx; + target_ulong pc_start; + uint16_t *gen_opc_end; + CPUBreakpoint *bp; + int j, lj = -1; + CPUMoxieState *env = &cpu->env; + + pc_start = tb->pc; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; + ctx.pc = pc_start; + ctx.saved_pc = -1; + ctx.tb = tb; + ctx.memidx = 0; + ctx.singlestep_enabled = 0; + ctx.bstate = BS_NONE; + + do { + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (ctx.pc == bp->pc) { + tcg_gen_movi_i32(cpu_pc, ctx.pc); + gen_helper_debug(cpu_env); + ctx.bstate = BS_EXCP; + goto done_generating; + } + } + } + + if (search_pc) { + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) { + tcg_ctx.gen_opc_instr_start[lj++] = 0; + } + } + tcg_ctx.gen_opc_pc[lj] = ctx.pc; + tcg_ctx.gen_opc_instr_start[lj] = 1; + } + ctx.opcode = cpu_lduw_code(env, ctx.pc); + ctx.pc += decode_opc(cpu, &ctx); + + if (env->singlestep_enabled) { + break; + } + + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) { + break; + } + } while (ctx.bstate == BS_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end); + + if (env->singlestep_enabled) { + tcg_gen_movi_tl(cpu_pc, ctx.pc); + gen_helper_debug(cpu_env); + } else { + switch (ctx.bstate) { + case BS_STOP: + case BS_NONE: + gen_goto_tb(env, &ctx, 0, ctx.pc); + break; + case BS_EXCP: + tcg_gen_exit_tb(0); + break; + case BS_BRANCH: + default: + break; + } + } + done_generating: + *tcg_ctx.gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; + lj++; + while (lj <= j) { + tcg_ctx.gen_opc_instr_start[lj++] = 0; + } + } else { + tb->size = ctx.pc - pc_start; + } +} + +void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(moxie_env_get_cpu(env), tb, false); +} + +void gen_intermediate_code_pc(CPUMoxieState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(moxie_env_get_cpu(env), tb, true); +} + +void restore_state_to_opc(CPUMoxieState *env, TranslationBlock *tb, int pc_pos) +{ + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; +} -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v7 1/4] Add moxie target code 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 1/4] Add moxie target code Anthony Green @ 2013-03-03 16:15 ` Blue Swirl 2013-03-03 22:09 ` Peter Maydell 1 sibling, 0 replies; 8+ messages in thread From: Blue Swirl @ 2013-03-03 16:15 UTC (permalink / raw) To: Anthony Green; +Cc: qemu-devel On Sun, Mar 3, 2013 at 1:07 PM, Anthony Green <green@moxielogic.com> wrote: > > Signed-off-by: Anthony Green <green@moxielogic.com> > --- > target-moxie/Makefile.objs | 2 + > target-moxie/cpu.c | 172 ++++++++ > target-moxie/cpu.h | 170 ++++++++ > target-moxie/helper.c | 170 ++++++++ > target-moxie/helper.h | 9 + > target-moxie/machine.c | 27 ++ > target-moxie/machine.h | 2 + > target-moxie/mmu.c | 36 ++ > target-moxie/mmu.h | 19 + > target-moxie/translate.c | 1003 ++++++++++++++++++++++++++++++++++++++++++++ > 10 files changed, 1610 insertions(+) > create mode 100644 target-moxie/Makefile.objs > create mode 100644 target-moxie/cpu.c > create mode 100644 target-moxie/cpu.h > create mode 100644 target-moxie/helper.c > create mode 100644 target-moxie/helper.h > create mode 100644 target-moxie/machine.c > create mode 100644 target-moxie/machine.h > create mode 100644 target-moxie/mmu.c > create mode 100644 target-moxie/mmu.h > create mode 100644 target-moxie/translate.c > > diff --git a/target-moxie/Makefile.objs b/target-moxie/Makefile.objs > new file mode 100644 > index 0000000..6381d4d > --- /dev/null > +++ b/target-moxie/Makefile.objs > @@ -0,0 +1,2 @@ > +obj-y += translate.o helper.o machine.o cpu.o machine.o > +obj-$(CONFIG_SOFTMMU) += mmu.o > diff --git a/target-moxie/cpu.c b/target-moxie/cpu.c > new file mode 100644 > index 0000000..c17d3f0 > --- /dev/null > +++ b/target-moxie/cpu.c > @@ -0,0 +1,172 @@ > +/* > + * 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) > diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h > new file mode 100644 > index 0000000..eb7354f > --- /dev/null > +++ b/target-moxie/cpu.h > @@ -0,0 +1,170 @@ > +/* > + * 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 > + > +#define CC_GT (1<<0) > +#define CC_LT (1<<1) > +#define CC_EQ (1<<2) > +#define CC_GTU (1<<3) > +#define CC_LTU (1<<4) > + > +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 */ > + uint32_t cc; /* condition codes */ > + > + 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)) > + > +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) > +{ > + CPUMoxieState *env = &MOXIE_CPU(cpu)->env; > + > + return env->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 */ > diff --git a/target-moxie/helper.c b/target-moxie/helper.c > new file mode 100644 > index 0000000..6de0598 > --- /dev/null > +++ b/target-moxie/helper.c > @@ -0,0 +1,170 @@ > +/* > + * 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, uint32_t pc, int ex) > +{ > + env->exception_index = ex; > + /* Stash the exception type. */ > + env->sregs[2] = ex; > + /* Stash the address where the exception occurred. */ > + env->sregs[5] = pc; > + /* Jump the the exception handline routine. */ > + env->pc = env->sregs[1]; > + cpu_loop_exit(env); > +} > + > +uint32_t helper_div(CPUMoxieState *env, uint32_t pc, uint32_t a, uint32_t b) > +{ > + if (unlikely(b == 0)) { > + helper_raise_exception(env, pc, 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 pc, uint32_t a, uint32_t b) > +{ > + if (unlikely(b == 0)) { > + helper_raise_exception(env, pc, 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) > +{ > + struct moxie_mmu_result_t res; Please use the typedef. > + 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; > + struct moxie_mmu_result_t res; > + int miss; > + miss = moxie_mmu_translate(&res, env, addr, 0, 0); > + if (!miss) { > + phy = res.phy; > + } > + return phy; > +} > +#endif > diff --git a/target-moxie/helper.h b/target-moxie/helper.h > new file mode 100644 > index 0000000..36ce126 > --- /dev/null > +++ b/target-moxie/helper.h > @@ -0,0 +1,9 @@ > +#include "exec/def-helper.h" > + > +DEF_HELPER_3(raise_exception, void, env, i32, int) > +DEF_HELPER_1(debug, void, env) > +DEF_HELPER_4(div, i32, env, i32, i32, i32) > +DEF_HELPER_4(udiv, i32, env, i32, i32, i32) > + > +#include "exec/def-helper.h" > + > diff --git a/target-moxie/machine.c b/target-moxie/machine.c > new file mode 100644 > index 0000000..b8ed253 > --- /dev/null > +++ b/target-moxie/machine.c > @@ -0,0 +1,27 @@ > +#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, 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); > +} > diff --git a/target-moxie/machine.h b/target-moxie/machine.h > new file mode 100644 > index 0000000..eeb1b73 > --- /dev/null > +++ b/target-moxie/machine.h > @@ -0,0 +1,2 @@ > +extern const VMStateDescription vmstate_moxie_cpu; > + > diff --git a/target-moxie/mmu.c b/target-moxie/mmu.c > new file mode 100644 > index 0000000..5217eed > --- /dev/null > +++ b/target-moxie/mmu.c > @@ -0,0 +1,36 @@ > +/* > + * 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; > +} > diff --git a/target-moxie/mmu.h b/target-moxie/mmu.h > new file mode 100644 > index 0000000..25a7609 > --- /dev/null > +++ b/target-moxie/mmu.h > @@ -0,0 +1,19 @@ > +#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 moxie_mmu_result_t { This should also be MoxieMMUResult. > + 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); > diff --git a/target-moxie/translate.c b/target-moxie/translate.c > new file mode 100644 > index 0000000..7ed4c0b > --- /dev/null > +++ b/target-moxie/translate.c > @@ -0,0 +1,1003 @@ > +/* > + * Moxie emulation for qemu: main translation routines. > + * > + * Copyright (c) 2009, 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/>. > + */ > + > +/* For information on the Moxie architecture, see > + * http://moxielogic.org/wiki The 21 patch bootstrap of a CPU and related toolchain was very interesting and entertaining read. Links for patch 17 are broken, btw. > + */ > + > +#include <stdarg.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <string.h> > +#include <inttypes.h> > +#include <assert.h> > + > +#include "cpu.h" > +#include "exec/exec-all.h" > +#include "disas/disas.h" > +#include "tcg-op.h" > + > +#include "helper.h" > +#define GEN_HELPER 1 > +#include "helper.h" > + > +/* This is the state at translation time. */ > +typedef struct DisasContext { > + struct TranslationBlock *tb; > + target_ulong pc, saved_pc; > + uint32_t opcode; > + uint32_t fp_status; > + /* Routine used to access memory */ > + int memidx; > + int bstate; > + target_ulong btarget; > + int singlestep_enabled; > +} DisasContext; > + > +enum { > + BS_NONE = 0, /* We go out of the TB without reaching a branch or an > + * exception condition */ > + BS_STOP = 1, /* We want to stop translation for any reason */ > + BS_BRANCH = 2, /* We reached a branch condition */ > + BS_EXCP = 3, /* We reached an exception condition */ > +}; > + > +static TCGv cpu_pc; > +static TCGv cpu_gregs[16]; > +static TCGv_ptr cpu_env; > +static TCGv cc; > + > +#define REG(x) (cpu_gregs[x]) > + > +/* Extract the signed 10-bit offset from a 16-bit branch > + instruction. */ > +#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1) > + > +void cpu_dump_state(CPUArchState *env, FILE *f, fprintf_function cpu_fprintf, > + int flags) > +{ > + int i; > + cpu_fprintf(f, "pc=0x%08x\n", env->pc); > + cpu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n", > + env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]); > + for (i = 4; i < 16; i += 4) { > + cpu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n", > + i-2, env->gregs[i], i-1, env->gregs[i + 1], > + i, env->gregs[i + 2], i+1, env->gregs[i + 3]); > + } > + cpu_fprintf(f, "sr0=0x%08x $r1=0x%08x\n", > + env->sregs[0], env->sregs[1]); > +} > + > +void moxie_translate_init(void) > +{ > + int i; > + static int done_init; > + static const char * const gregnames[16] = { > + "$fp", "$sp", "$r0", "$r1", > + "$r2", "$r3", "$r4", "$r5", > + "$r6", "$r7", "$r8", "$r9", > + "$r10", "$r11", "$r12", "$r13" > + }; > + > + if (done_init) { > + return; > + } > + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); > + cpu_pc = tcg_global_mem_new_i32(TCG_AREG0, > + offsetof(CPUMoxieState, pc), "$pc"); > + for (i = 0; i < 24; i++) > + cpu_gregs[i] = tcg_global_mem_new_i32(TCG_AREG0, > + offsetof(CPUMoxieState, gregs[i]), > + gregnames[i]); > + > + cc = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUMoxieState, cc), "cc"); > + > + done_init = 1; > +} > + > +static inline void gen_goto_tb(CPUMoxieState *env, DisasContext *ctx, > + int n, target_ulong dest) > +{ > + TranslationBlock *tb; > + tb = ctx->tb; > + > + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && > + !ctx->singlestep_enabled) { > + tcg_gen_goto_tb(n); > + tcg_gen_movi_i32(cpu_pc, dest); > + tcg_gen_exit_tb((long) tb + n); > + } else { > + tcg_gen_movi_i32(cpu_pc, dest); > + if (ctx->singlestep_enabled) { > + gen_helper_debug(cpu_env); > + } > + tcg_gen_exit_tb(0); > + } > +} > + > +static int decode_opc(MoxieCPU *cpu, DisasContext *ctx) > +{ > + CPUMoxieState *env = &cpu->env; > + > + /* Local cache for the instruction opcode. */ > + int opcode; > + /* Set the default instruction length. */ > + int length = 2; > + > + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { > + tcg_gen_debug_insn_start(ctx->pc); > + } > + > + /* Examine the 16-bit opcode. */ > + opcode = ctx->opcode; > + > + /* Decode instruction. */ > + if (opcode & (1 << 15)) { > + if (opcode & (1 << 14)) { > + /* This is a Form 3 instruction. */ > + int inst = (opcode >> 10 & 0xf); > + > + switch (inst) { > + case 0x00: /* beq */ > + { > + int l1 = gen_new_label(); > + tcg_gen_brcondi_i32(TCG_COND_EQ, cc, CC_EQ, l1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x01: /* bne */ > + { > + int l1 = gen_new_label(); > + tcg_gen_brcondi_i32(TCG_COND_NE, cc, CC_EQ, l1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x02: /* blt */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_LT); > + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_LT, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x03: /* bgt */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_GT); > + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_GT, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x04: /* bltu */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_LTU); > + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_LTU, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x05: /* bgtu */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_GTU); > + tcg_gen_brcondi_i32(TCG_COND_EQ, t1, CC_GTU, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x06: /* bge */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_GT|CC_EQ); > + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x07: /* ble */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_LT|CC_EQ); > + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x08: /* bgeu */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_GTU|CC_EQ); > + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x09: /* bleu */ > + { > + int l1 = gen_new_label(); > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_andi_i32(t1, cc, CC_LTU|CC_EQ); > + tcg_gen_brcondi_i32(TCG_COND_GT, t1, 0, l1); > + tcg_temp_free_i32(t1); > + gen_goto_tb(env, ctx, 1, ctx->pc + 2); > + gen_set_label(l1); > + gen_goto_tb(env, ctx, 0, INST2OFFSET(opcode) + ctx->pc + 2); > + ctx->bstate = BS_BRANCH; > + } > + break; > + default: > + { > + TCGv temp = tcg_temp_new_i32(); > + tcg_gen_movi_i32(cpu_pc, ctx->pc); > + tcg_gen_movi_i32(temp, MOXIE_EX_BAD); > + gen_helper_raise_exception(cpu_env, cpu_pc, temp); > + tcg_temp_free_i32(temp); > + } > + break; > + } > + } else { > + /* This is a Form 2 instruction. */ > + int inst = (opcode >> 12 & 0x3); > + switch (inst) { > + case 0x00: /* inc */ > + { > + int a = (opcode >> 8) & 0xf; > + unsigned int v = (opcode & 0xff); > + tcg_gen_addi_i32(REG(a), REG(a), v); > + } > + break; > + case 0x01: /* dec */ > + { > + int a = (opcode >> 8) & 0xf; > + unsigned int v = (opcode & 0xff); > + tcg_gen_subi_i32(REG(a), REG(a), v); > + } > + break; > + case 0x02: /* gsr */ > + { > + int a = (opcode >> 8) & 0xf; > + unsigned v = (opcode & 0xff); > + tcg_gen_ld_i32(REG(a), cpu_env, > + offsetof(CPUMoxieState, sregs[v])); > + } > + break; > + case 0x03: /* ssr */ > + { > + int a = (opcode >> 8) & 0xf; > + unsigned v = (opcode & 0xff); > + tcg_gen_st_i32(REG(a), cpu_env, > + offsetof(CPUMoxieState, sregs[v])); > + } > + break; > + default: > + { > + TCGv temp = tcg_temp_new_i32(); > + tcg_gen_movi_i32(cpu_pc, ctx->pc); > + tcg_gen_movi_i32(temp, MOXIE_EX_BAD); > + gen_helper_raise_exception(cpu_env, cpu_pc, temp); > + tcg_temp_free_i32(temp); > + } > + break; > + } > + } > + } else { > + /* This is a Form 1 instruction. */ > + int inst = opcode >> 8; > + switch (inst) { > + case 0x00: /* nop */ > + break; > + case 0x01: /* ldi.l (immediate) */ > + { > + int reg = (opcode >> 4) & 0xf; > + int val = cpu_ldl_code(env, ctx->pc + 2); > + tcg_gen_movi_i32(REG(reg), val); > + length = 6; > + } > + break; > + case 0x02: /* mov (register-to-register) */ > + { > + int dest = (opcode >> 4) & 0xf; > + int src = opcode & 0xf; > + tcg_gen_mov_i32(REG(dest), REG(src)); > + } > + break; > + case 0x03: /* jsra */ > + { > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + > + tcg_gen_movi_i32(t1, ctx->pc + 6); > + > + /* Make space for the static chain and return address. */ > + tcg_gen_subi_i32(t2, REG(1), 8); > + tcg_gen_mov_i32(REG(1), t2); > + tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); > + > + /* Push the current frame pointer. */ > + tcg_gen_subi_i32(t2, REG(1), 4); > + tcg_gen_mov_i32(REG(1), t2); > + tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); > + > + /* Set the pc and $fp. */ > + tcg_gen_mov_i32(REG(0), REG(1)); > + > + gen_goto_tb(env, ctx, 0, cpu_ldl_code(env, ctx->pc + 2)); > + > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + > + ctx->bstate = BS_BRANCH; > + length = 6; > + } > + break; > + case 0x04: /* ret */ > + { > + TCGv t1 = tcg_temp_new_i32(); > + > + /* The new $sp is the old $fp. */ > + tcg_gen_mov_i32(REG(1), REG(0)); > + > + /* Pop the frame pointer. */ > + tcg_gen_qemu_ld32u(REG(0), REG(1), ctx->memidx); > + tcg_gen_addi_i32(t1, REG(1), 4); > + tcg_gen_mov_i32(REG(1), t1); > + > + > + /* Pop the return address and skip over the static chain > + slot. */ > + tcg_gen_qemu_ld32u(cpu_pc, REG(1), ctx->memidx); > + tcg_gen_addi_i32(t1, REG(1), 8); > + tcg_gen_mov_i32(REG(1), t1); > + > + tcg_temp_free_i32(t1); > + > + /* Jump... */ > + tcg_gen_exit_tb(0); > + > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x05: /* add.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_add_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x06: /* push */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + TCGv t1 = tcg_temp_new_i32(); > + tcg_gen_subi_i32(t1, REG(a), 4); > + tcg_gen_mov_i32(REG(a), t1); > + tcg_gen_qemu_st32(REG(b), REG(a), ctx->memidx); > + tcg_temp_free_i32(t1); > + } > + break; > + case 0x07: /* pop */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + TCGv t1 = tcg_temp_new_i32(); > + > + tcg_gen_qemu_ld32u(REG(b), REG(a), ctx->memidx); > + tcg_gen_addi_i32(t1, REG(a), 4); > + tcg_gen_mov_i32(REG(a), t1); > + tcg_temp_free_i32(t1); > + } > + break; > + case 0x08: /* lda.l */ > + { > + int reg = (opcode >> 4) & 0xf; > + > + TCGv ptr = tcg_temp_new_i32(); > + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_ld32u(REG(reg), ptr, ctx->memidx); > + tcg_temp_free_i32(ptr); > + > + length = 6; > + } > + break; > + case 0x09: /* sta.l */ > + { > + int val = (opcode >> 4) & 0xf; > + > + TCGv ptr = tcg_temp_new_i32(); > + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_st32(REG(val), ptr, ctx->memidx); > + tcg_temp_free_i32(ptr); > + > + length = 6; > + } > + break; > + case 0x0a: /* ld.l (register indirect) */ > + { > + int src = opcode & 0xf; > + int dest = (opcode >> 4) & 0xf; > + > + tcg_gen_qemu_ld32u(REG(dest), REG(src), ctx->memidx); > + } > + break; > + case 0x0b: /* st.l */ > + { > + int dest = (opcode >> 4) & 0xf; > + int val = opcode & 0xf; > + > + tcg_gen_qemu_st32(REG(val), REG(dest), ctx->memidx); > + } > + break; > + case 0x0c: /* ldo.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_ld32u(t2, t1, ctx->memidx); > + tcg_gen_mov_i32(REG(a), t2); > + > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + > + length = 6; > + } > + break; > + case 0x0d: /* sto.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_st32(REG(b), t1, ctx->memidx); > + > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + > + length = 6; > + } > + break; > + case 0x0e: /* cmp */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + int label_equal = gen_new_label(); > + int label_done = gen_new_label(); > + > + /* Clear CC */ > + tcg_gen_movi_i32(cc, 0); > + > + tcg_gen_brcond_i32(TCG_COND_EQ, REG(a), REG(b), label_equal); > + > +#define CMPTEST(t, CODE) \ > + { \ > + int lyes = gen_new_label(); \ > + int lno = gen_new_label(); \ > + tcg_gen_brcond_i32(t, REG(a), REG(b), lyes); \ > + tcg_gen_br(lno); \ > + gen_set_label(lyes); \ > + tcg_gen_ori_i32(cc, cc, CODE); \ > + gen_set_label(lno); \ > + } > + CMPTEST(TCG_COND_LT, CC_LT); > + CMPTEST(TCG_COND_GT, CC_GT); > + CMPTEST(TCG_COND_LTU, CC_LTU); > + CMPTEST(TCG_COND_GTU, CC_GTU); > + tcg_gen_br(label_done); > + gen_set_label(label_equal); > + tcg_gen_movi_i32(cc, CC_EQ); > + gen_set_label(label_done); > + } > + break; > + case 0x19: /* jsr */ > + { > + int fnreg = (opcode >> 4) & 0xf; > + > + /* Load the stack pointer into T0. */ > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + > + tcg_gen_movi_i32(t1, ctx->pc + 2); > + > + /* Make space for the static chain and return address. */ > + tcg_gen_subi_i32(t2, REG(1), 8); > + tcg_gen_mov_i32(REG(1), t2); > + tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); > + > + /* Push the current frame pointer. */ > + tcg_gen_subi_i32(t2, REG(1), 4); > + tcg_gen_mov_i32(REG(1), t2); > + tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); > + > + /* Set the pc and $fp. */ > + tcg_gen_mov_i32(REG(0), REG(1)); > + tcg_gen_mov_i32(cpu_pc, REG(fnreg)); > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + tcg_gen_exit_tb(0); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x1a: /* jmpa */ > + { > + tcg_gen_movi_i32(cpu_pc, cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_exit_tb(0); > + ctx->bstate = BS_BRANCH; > + length = 6; > + } > + break; > + case 0x1b: /* ldi.b (immediate) */ > + { > + int reg = (opcode >> 4) & 0xf; > + int val = cpu_ldl_code(env, ctx->pc + 2); > + tcg_gen_movi_i32(REG(reg), val); > + length = 6; > + } > + break; > + case 0x1c: /* ld.b (register indirect) */ > + { > + int src = opcode & 0xf; > + int dest = (opcode >> 4) & 0xf; > + > + tcg_gen_qemu_ld8u(REG(dest), REG(src), ctx->memidx); > + } > + break; > + case 0x1d: /* lda.b */ > + { > + int reg = (opcode >> 4) & 0xf; > + > + TCGv ptr = tcg_temp_new_i32(); > + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_ld8u(REG(reg), ptr, ctx->memidx); > + tcg_temp_free_i32(ptr); > + > + length = 6; > + } > + break; > + case 0x1e: /* st.b */ > + { > + int dest = (opcode >> 4) & 0xf; > + int val = opcode & 0xf; > + > + tcg_gen_qemu_st8(REG(val), REG(dest), ctx->memidx); > + } > + break; > + case 0x1f: /* sta.b */ > + { > + int val = (opcode >> 4) & 0xf; > + > + TCGv ptr = tcg_temp_new_i32(); > + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_st8(REG(val), ptr, ctx->memidx); > + tcg_temp_free_i32(ptr); > + > + length = 6; > + } > + break; > + case 0x20: /* ldi.s (immediate) */ > + { > + int reg = (opcode >> 4) & 0xf; > + int val = cpu_ldl_code(env, ctx->pc + 2); > + tcg_gen_movi_i32(REG(reg), val); > + length = 6; > + } > + break; > + case 0x21: /* ld.s (register indirect) */ > + { > + int src = opcode & 0xf; > + int dest = (opcode >> 4) & 0xf; > + > + tcg_gen_qemu_ld16u(REG(dest), REG(src), ctx->memidx); > + } > + break; > + case 0x22: /* lda.s */ > + { > + int reg = (opcode >> 4) & 0xf; > + > + TCGv ptr = tcg_temp_new_i32(); > + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_ld16u(REG(reg), ptr, ctx->memidx); > + tcg_temp_free_i32(ptr); > + > + length = 6; > + } > + break; > + case 0x23: /* st.s */ > + { > + int dest = (opcode >> 4) & 0xf; > + int val = opcode & 0xf; > + > + tcg_gen_qemu_st16(REG(val), REG(dest), ctx->memidx); > + } > + break; > + case 0x24: /* sta.s */ > + { > + int val = (opcode >> 4) & 0xf; > + > + TCGv ptr = tcg_temp_new_i32(); > + tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_st16(REG(val), ptr, ctx->memidx); > + tcg_temp_free_i32(ptr); > + > + length = 6; > + } > + break; > + case 0x25: /* jmp */ > + { > + int reg = (opcode >> 4) & 0xf; > + tcg_gen_mov_i32(cpu_pc, REG(reg)); > + tcg_gen_exit_tb(0); > + ctx->bstate = BS_BRANCH; > + } > + break; > + case 0x26: /* and */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_and_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x27: /* lshr */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_shr_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x28: /* ashl */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_shl_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x29: /* sub.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_sub_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x2a: /* neg */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_neg_i32(REG(a), REG(b)); > + } > + break; > + case 0x2b: /* or */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_or_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x2c: /* not */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_not_i32(REG(a), REG(b)); > + } > + break; > + case 0x2d: /* ashr */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_sar_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x2e: /* xor */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_xor_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x2f: /* mul.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + tcg_gen_mul_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x30: /* swi */ > + { > + int val = cpu_ldl_code(env, ctx->pc + 2); > + > + TCGv temp = tcg_temp_new_i32(); > + tcg_gen_movi_i32(temp, val); > + tcg_gen_st_i32(temp, cpu_env, > + offsetof(CPUMoxieState, sregs[3])); > + tcg_gen_movi_i32(cpu_pc, ctx->pc); > + tcg_gen_movi_i32(temp, MOXIE_EX_SWI); > + gen_helper_raise_exception(cpu_env, cpu_pc, temp); > + tcg_temp_free_i32(temp); > + > + length = 6; > + } > + break; > + case 0x31: /* div.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + tcg_gen_movi_i32(cpu_pc, ctx->pc); > + gen_helper_div(REG(a), cpu_env, cpu_pc, REG(a), REG(b)); > + } > + break; > + case 0x32: /* udiv.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + tcg_gen_movi_i32(cpu_pc, ctx->pc); > + gen_helper_udiv(REG(a), cpu_env, cpu_pc, REG(a), REG(b)); > + } > + break; > + case 0x33: /* mod.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + tcg_gen_rem_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x34: /* umod.l */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + tcg_gen_remu_i32(REG(a), REG(a), REG(b)); > + } > + break; > + case 0x35: /* brk */ > + { > + gen_helper_debug(cpu_env); > + } > + break; > + case 0x36: /* ldo.b */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_ld8u(t2, t1, ctx->memidx); > + tcg_gen_mov_i32(REG(a), t2); > + > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + > + length = 6; > + } > + break; > + case 0x37: /* sto.b */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_st8(REG(b), t1, ctx->memidx); > + > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + > + length = 6; > + } > + break; > + case 0x38: /* ldo.s */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_ld16u(t2, t1, ctx->memidx); > + tcg_gen_mov_i32(REG(a), t2); > + > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + > + length = 6; > + } > + break; > + case 0x39: /* sto.s */ > + { > + int a = (opcode >> 4) & 0xf; > + int b = opcode & 0xf; > + > + TCGv t1 = tcg_temp_new_i32(); > + TCGv t2 = tcg_temp_new_i32(); > + tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc + 2)); > + tcg_gen_qemu_st16(REG(b), t1, ctx->memidx); > + tcg_temp_free_i32(t1); > + tcg_temp_free_i32(t2); > + > + length = 6; > + } > + break; > + default: > + { > + TCGv temp = tcg_temp_new_i32(); > + tcg_gen_movi_i32(cpu_pc, ctx->pc); > + tcg_gen_movi_i32(temp, MOXIE_EX_BAD); > + gen_helper_raise_exception(cpu_env, cpu_pc, temp); > + tcg_temp_free_i32(temp); > + } > + break; > + } > + } > + > + return length; > +} > + > +/* generate intermediate code for basic block 'tb'. */ > +static void > +gen_intermediate_code_internal(MoxieCPU *cpu, TranslationBlock *tb, > + bool search_pc) > +{ > + DisasContext ctx; > + target_ulong pc_start; > + uint16_t *gen_opc_end; > + CPUBreakpoint *bp; > + int j, lj = -1; > + CPUMoxieState *env = &cpu->env; > + > + pc_start = tb->pc; > + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; > + ctx.pc = pc_start; > + ctx.saved_pc = -1; > + ctx.tb = tb; > + ctx.memidx = 0; > + ctx.singlestep_enabled = 0; > + ctx.bstate = BS_NONE; > + > + do { > + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { > + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { > + if (ctx.pc == bp->pc) { > + tcg_gen_movi_i32(cpu_pc, ctx.pc); > + gen_helper_debug(cpu_env); > + ctx.bstate = BS_EXCP; > + goto done_generating; > + } > + } > + } > + > + if (search_pc) { > + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; > + if (lj < j) { > + lj++; > + while (lj < j) { > + tcg_ctx.gen_opc_instr_start[lj++] = 0; > + } > + } > + tcg_ctx.gen_opc_pc[lj] = ctx.pc; > + tcg_ctx.gen_opc_instr_start[lj] = 1; > + } > + ctx.opcode = cpu_lduw_code(env, ctx.pc); > + ctx.pc += decode_opc(cpu, &ctx); > + > + if (env->singlestep_enabled) { > + break; > + } > + > + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) { > + break; > + } > + } while (ctx.bstate == BS_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end); > + > + if (env->singlestep_enabled) { > + tcg_gen_movi_tl(cpu_pc, ctx.pc); > + gen_helper_debug(cpu_env); > + } else { > + switch (ctx.bstate) { > + case BS_STOP: > + case BS_NONE: > + gen_goto_tb(env, &ctx, 0, ctx.pc); > + break; > + case BS_EXCP: > + tcg_gen_exit_tb(0); > + break; > + case BS_BRANCH: > + default: > + break; > + } > + } > + done_generating: > + *tcg_ctx.gen_opc_ptr = INDEX_op_end; > + if (search_pc) { > + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; > + lj++; > + while (lj <= j) { > + tcg_ctx.gen_opc_instr_start[lj++] = 0; > + } > + } else { > + tb->size = ctx.pc - pc_start; > + } > +} > + > +void gen_intermediate_code(CPUMoxieState *env, struct TranslationBlock *tb) > +{ > + gen_intermediate_code_internal(moxie_env_get_cpu(env), tb, false); > +} > + > +void gen_intermediate_code_pc(CPUMoxieState *env, struct TranslationBlock *tb) > +{ > + gen_intermediate_code_internal(moxie_env_get_cpu(env), tb, true); > +} > + > +void restore_state_to_opc(CPUMoxieState *env, TranslationBlock *tb, int pc_pos) > +{ > + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; > +} > -- > 1.8.1.4 > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v7 1/4] Add moxie target code 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 1/4] Add moxie target code Anthony Green 2013-03-03 16:15 ` Blue Swirl @ 2013-03-03 22:09 ` Peter Maydell 1 sibling, 0 replies; 8+ messages in thread From: Peter Maydell @ 2013-03-03 22:09 UTC (permalink / raw) To: Anthony Green; +Cc: qemu-devel On 3 March 2013 21:07, Anthony Green <green@moxielogic.com> wrote: > +/* generate intermediate code for basic block 'tb'. */ > +static void > +gen_intermediate_code_internal(MoxieCPU *cpu, TranslationBlock *tb, > + bool search_pc) > +{ > + DisasContext ctx; > + target_ulong pc_start; > + uint16_t *gen_opc_end; > + CPUBreakpoint *bp; > + int j, lj = -1; > + CPUMoxieState *env = &cpu->env; > + > + pc_start = tb->pc; > + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; > + ctx.pc = pc_start; > + ctx.saved_pc = -1; > + ctx.tb = tb; > + ctx.memidx = 0; > + ctx.singlestep_enabled = 0; > + ctx.bstate = BS_NONE; > + > + do { > + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { > + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { > + if (ctx.pc == bp->pc) { > + tcg_gen_movi_i32(cpu_pc, ctx.pc); > + gen_helper_debug(cpu_env); > + ctx.bstate = BS_EXCP; > + goto done_generating; > + } > + } > + } > + > + if (search_pc) { > + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; > + if (lj < j) { > + lj++; > + while (lj < j) { > + tcg_ctx.gen_opc_instr_start[lj++] = 0; > + } > + } > + tcg_ctx.gen_opc_pc[lj] = ctx.pc; > + tcg_ctx.gen_opc_instr_start[lj] = 1; > + } > + ctx.opcode = cpu_lduw_code(env, ctx.pc); > + ctx.pc += decode_opc(cpu, &ctx); > + > + if (env->singlestep_enabled) { > + break; > + } > + > + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) { > + break; > + } > + } while (ctx.bstate == BS_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end); > + > + if (env->singlestep_enabled) { > + tcg_gen_movi_tl(cpu_pc, ctx.pc); > + gen_helper_debug(cpu_env); > + } else { > + switch (ctx.bstate) { > + case BS_STOP: > + case BS_NONE: > + gen_goto_tb(env, &ctx, 0, ctx.pc); > + break; > + case BS_EXCP: > + tcg_gen_exit_tb(0); > + break; > + case BS_BRANCH: > + default: > + break; > + } > + } > + done_generating: > + *tcg_ctx.gen_opc_ptr = INDEX_op_end; > + if (search_pc) { > + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; > + lj++; > + while (lj <= j) { > + tcg_ctx.gen_opc_instr_start[lj++] = 0; > + } > + } else { > + tb->size = ctx.pc - pc_start; > + } > +} Now that my 'get rid of cpu_tb_unlink()' patch series has been applied, you must call 'gen_tb_start()' and 'gen_tb_end()' in the right places in this function, or interrupts will not be able to stop QEMU executing translated code. thanks -- PMM ^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v7 2/4] Add moxie disassembler 2013-03-03 13:07 [Qemu-devel] [PATCH v7 0/4] Moxie CPU port Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 1/4] Add moxie target code Anthony Green @ 2013-03-03 13:07 ` Anthony Green 2013-03-03 15:52 ` Blue Swirl 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 3/4] Add sample moxie system Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 4/4] Add top level changes for moxie Anthony Green 3 siblings, 1 reply; 8+ messages in thread From: Anthony Green @ 2013-03-03 13:07 UTC (permalink / raw) To: qemu-devel; +Cc: Anthony Green Signed-off-by: Anthony Green <green@moxielogic.com> --- disas.c | 6 + disas/Makefile.objs | 1 + disas/moxie.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/disas/bfd.h | 66 +++++----- 4 files changed, 401 insertions(+), 32 deletions(-) create mode 100644 disas/moxie.c diff --git a/disas.c b/disas.c index a46faee..74d3ba0 100644 --- a/disas.c +++ b/disas.c @@ -256,6 +256,9 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code, #elif defined(TARGET_MICROBLAZE) s.info.mach = bfd_arch_microblaze; print_insn = print_insn_microblaze; +#elif defined(TARGET_MOXIE) + s.info.mach = bfd_arch_moxie; + print_insn = print_insn_moxie; #elif defined(TARGET_LM32) s.info.mach = bfd_mach_lm32; print_insn = print_insn_lm32; @@ -462,6 +465,9 @@ void monitor_disas(Monitor *mon, CPUArchState *env, #elif defined(TARGET_S390X) s.info.mach = bfd_mach_s390_64; print_insn = print_insn_s390; +#elif defined(TARGET_MOXIE) + s.info.mach = bfd_arch_moxie; + print_insn = print_insn_moxie; #elif defined(TARGET_LM32) s.info.mach = bfd_mach_lm32; print_insn = print_insn_lm32; diff --git a/disas/Makefile.objs b/disas/Makefile.objs index ed75f9a..3b1e77a 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -7,6 +7,7 @@ common-obj-$(CONFIG_IA64_DIS) += ia64.o common-obj-$(CONFIG_M68K_DIS) += m68k.o common-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o common-obj-$(CONFIG_MIPS_DIS) += mips.o +common-obj-$(CONFIG_MOXIE_DIS) += moxie.o common-obj-$(CONFIG_PPC_DIS) += ppc.o common-obj-$(CONFIG_S390_DIS) += s390.o common-obj-$(CONFIG_SH4_DIS) += sh4.o diff --git a/disas/moxie.c b/disas/moxie.c new file mode 100644 index 0000000..4c5f180 --- /dev/null +++ b/disas/moxie.c @@ -0,0 +1,360 @@ +/* Disassemble moxie instructions. + Copyright (c) 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 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> +#define STATIC_TABLE +#define DEFINE_TABLE + +#include "disas/bfd.h" + +static void *stream; + +/* Form 1 instructions come in different flavors: + + Some have no arguments (MOXIE_F1_NARG) + Some only use the A operand (MOXIE_F1_A) + Some use A and B registers (MOXIE_F1_AB) + Some use A and consume a 4 byte immediate value (MOXIE_F1_A4) + Some use just a 4 byte immediate value (MOXIE_F1_4) + Some use just a 4 byte memory address (MOXIE_F1_M) + Some use B and an indirect A (MOXIE_F1_AiB) + Some use A and an indirect B (MOXIE_F1_ABi) + Some consume a 4 byte immediate value and use X (MOXIE_F1_4A) + Some use B and an indirect A plus 4 bytes (MOXIE_F1_AiB4) + Some use A and an indirect B plus 4 bytes (MOXIE_F1_ABi4) + + Form 2 instructions also come in different flavors: + + Some have no arguments (MOXIE_F2_NARG) + Some use the A register and an 8-bit value (MOXIE_F2_A8V) + + Form 3 instructions also come in different flavors: + + Some have no arguments (MOXIE_F3_NARG) + Some have a 10-bit PC relative operand (MOXIE_F3_PCREL). */ + +#define MOXIE_F1_NARG 0x100 +#define MOXIE_F1_A 0x101 +#define MOXIE_F1_AB 0x102 +/* #define MOXIE_F1_ABC 0x103 */ +#define MOXIE_F1_A4 0x104 +#define MOXIE_F1_4 0x105 +#define MOXIE_F1_AiB 0x106 +#define MOXIE_F1_ABi 0x107 +#define MOXIE_F1_4A 0x108 +#define MOXIE_F1_AiB4 0x109 +#define MOXIE_F1_ABi4 0x10a +#define MOXIE_F1_M 0x10b + +#define MOXIE_F2_NARG 0x200 +#define MOXIE_F2_A8V 0x201 + +#define MOXIE_F3_NARG 0x300 +#define MOXIE_F3_PCREL 0x301 + +typedef struct moxie_opc_info_t { + short opcode; + unsigned itype; + const char * name; +} moxie_opc_info_t; + +extern const moxie_opc_info_t moxie_form1_opc_info[64]; +extern const moxie_opc_info_t moxie_form2_opc_info[4]; +extern const moxie_opc_info_t moxie_form3_opc_info[16]; + +/* The moxie processor's 16-bit instructions come in two forms: + + FORM 1 instructions start with a 0 bit... + + 0oooooooaaaabbbb + 0 F + + ooooooo - form 1 opcode number + aaaa - operand A + bbbb - operand B + + FORM 2 instructions start with bits "10"... + + 10ooaaaavvvvvvvv + 0 F + + oo - form 2 opcode number + aaaa - operand A + vvvvvvvv - 8-bit immediate value + + FORM 3 instructions start with a bits "11"... + + 11oooovvvvvvvvvv + 0 F + + oooo - form 3 opcode number + vvvvvvvvvv - 10-bit immediate value. */ + +const moxie_opc_info_t moxie_form1_opc_info[64] = + { + { 0x00, MOXIE_F1_NARG, "nop" }, + { 0x01, MOXIE_F1_A4, "ldi.l" }, + { 0x02, MOXIE_F1_AB, "mov" }, + { 0x03, MOXIE_F1_M, "jsra" }, + { 0x04, MOXIE_F1_NARG, "ret" }, + { 0x05, MOXIE_F1_AB, "add.l" }, + { 0x06, MOXIE_F1_AB, "push" }, + { 0x07, MOXIE_F1_AB, "pop" }, + { 0x08, MOXIE_F1_A4, "lda.l" }, + { 0x09, MOXIE_F1_4A, "sta.l" }, + { 0x0a, MOXIE_F1_ABi, "ld.l" }, + { 0x0b, MOXIE_F1_AiB, "st.l" }, + { 0x0c, MOXIE_F1_ABi4, "ldo.l" }, + { 0x0d, MOXIE_F1_AiB4, "sto.l" }, + { 0x0e, MOXIE_F1_AB, "cmp" }, + { 0x0f, MOXIE_F1_NARG, "bad" }, + { 0x10, MOXIE_F1_NARG, "bad" }, + { 0x11, MOXIE_F1_NARG, "bad" }, + { 0x12, MOXIE_F1_NARG, "bad" }, + { 0x13, MOXIE_F1_NARG, "bad" }, + { 0x14, MOXIE_F1_NARG, "bad" }, + { 0x15, MOXIE_F1_NARG, "bad" }, + { 0x16, MOXIE_F1_NARG, "bad" }, + { 0x17, MOXIE_F1_NARG, "bad" }, + { 0x18, MOXIE_F1_NARG, "bad" }, + { 0x19, MOXIE_F1_A, "jsr" }, + { 0x1a, MOXIE_F1_M, "jmpa" }, + { 0x1b, MOXIE_F1_A4, "ldi.b" }, + { 0x1c, MOXIE_F1_ABi, "ld.b" }, + { 0x1d, MOXIE_F1_A4, "lda.b" }, + { 0x1e, MOXIE_F1_AiB, "st.b" }, + { 0x1f, MOXIE_F1_4A, "sta.b" }, + { 0x20, MOXIE_F1_A4, "ldi.s" }, + { 0x21, MOXIE_F1_ABi, "ld.s" }, + { 0x22, MOXIE_F1_A4, "lda.s" }, + { 0x23, MOXIE_F1_AiB, "st.s" }, + { 0x24, MOXIE_F1_4A, "sta.s" }, + { 0x25, MOXIE_F1_A, "jmp" }, + { 0x26, MOXIE_F1_AB, "and" }, + { 0x27, MOXIE_F1_AB, "lshr" }, + { 0x28, MOXIE_F1_AB, "ashl" }, + { 0x29, MOXIE_F1_AB, "sub.l" }, + { 0x2a, MOXIE_F1_AB, "neg" }, + { 0x2b, MOXIE_F1_AB, "or" }, + { 0x2c, MOXIE_F1_AB, "not" }, + { 0x2d, MOXIE_F1_AB, "ashr" }, + { 0x2e, MOXIE_F1_AB, "xor" }, + { 0x2f, MOXIE_F1_AB, "mul.l" }, + { 0x30, MOXIE_F1_4, "swi" }, + { 0x31, MOXIE_F1_AB, "div.l" }, + { 0x32, MOXIE_F1_AB, "udiv.l" }, + { 0x33, MOXIE_F1_AB, "mod.l" }, + { 0x34, MOXIE_F1_AB, "umod.l" }, + { 0x35, MOXIE_F1_NARG, "brk" }, + { 0x36, MOXIE_F1_ABi4, "ldo.b" }, + { 0x37, MOXIE_F1_AiB4, "sto.b" }, + { 0x38, MOXIE_F1_ABi4, "ldo.s" }, + { 0x39, MOXIE_F1_AiB4, "sto.s" }, + { 0x3a, MOXIE_F1_NARG, "bad" }, + { 0x3b, MOXIE_F1_NARG, "bad" }, + { 0x3c, MOXIE_F1_NARG, "bad" }, + { 0x3d, MOXIE_F1_NARG, "bad" }, + { 0x3e, MOXIE_F1_NARG, "bad" }, + { 0x3f, MOXIE_F1_NARG, "bad" } + }; + +const moxie_opc_info_t moxie_form2_opc_info[4] = + { + { 0x00, MOXIE_F2_A8V, "inc" }, + { 0x01, MOXIE_F2_A8V, "dec" }, + { 0x02, MOXIE_F2_A8V, "gsr" }, + { 0x03, MOXIE_F2_A8V, "ssr" } + }; + +const moxie_opc_info_t moxie_form3_opc_info[16] = + { + { 0x00, MOXIE_F3_PCREL,"beq" }, + { 0x01, MOXIE_F3_PCREL,"bne" }, + { 0x02, MOXIE_F3_PCREL,"blt" }, + { 0x03, MOXIE_F3_PCREL,"bgt" }, + { 0x04, MOXIE_F3_PCREL,"bltu" }, + { 0x05, MOXIE_F3_PCREL,"bgtu" }, + { 0x06, MOXIE_F3_PCREL,"bge" }, + { 0x07, MOXIE_F3_PCREL,"ble" }, + { 0x08, MOXIE_F3_PCREL,"bgeu" }, + { 0x09, MOXIE_F3_PCREL,"bleu" }, + { 0x0a, MOXIE_F3_NARG, "bad" }, + { 0x0b, MOXIE_F3_NARG, "bad" }, + { 0x0c, MOXIE_F3_NARG, "bad" }, + { 0x0d, MOXIE_F3_NARG, "bad" }, + { 0x0e, MOXIE_F3_NARG, "bad" }, + { 0x0f, MOXIE_F3_NARG, "bad" } + }; + +/* Macros to extract operands from the instruction word. */ +#define OP_A(i) ((i >> 4) & 0xf) +#define OP_B(i) (i & 0xf) +#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1) + +static const char * reg_names[16] = + { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", + "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" }; + +int +print_insn_moxie(bfd_vma addr, struct disassemble_info * info) +{ + int length = 2; + int status; + stream = info->stream; + const moxie_opc_info_t * opcode; + bfd_byte buffer[4]; + unsigned short iword; + fprintf_function fpr = info->fprintf_func; + + if ((status = info->read_memory_func(addr, buffer, 2, info))) + goto fail; + iword = (bfd_getb16(buffer) >> 16); + + /* Form 1 instructions have the high bit set to 0. */ + if ((iword & (1<<15)) == 0) { + /* Extract the Form 1 opcode. */ + opcode = &moxie_form1_opc_info[iword >> 8]; + switch (opcode->itype) { + case MOXIE_F1_NARG: + fpr(stream, "%s", opcode->name); + break; + case MOXIE_F1_A: + fpr(stream, "%s\t%s", opcode->name, + reg_names[OP_A(iword)]); + break; + case MOXIE_F1_AB: + fpr(stream, "%s\t%s, %s", opcode->name, + reg_names[OP_A(iword)], + reg_names[OP_B(iword)]); + break; + case MOXIE_F1_A4: + { + unsigned imm; + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) + goto fail; + imm = bfd_getb32(buffer); + fpr(stream, "%s\t%s, 0x%x", opcode->name, + reg_names[OP_A(iword)], imm); + length = 6; + } + break; + case MOXIE_F1_4: + { + unsigned imm; + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) + goto fail; + imm = bfd_getb32(buffer); + fpr(stream, "%s\t0x%x", opcode->name, imm); + length = 6; + } + break; + case MOXIE_F1_M: + { + unsigned imm; + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) + goto fail; + imm = bfd_getb32(buffer); + fpr(stream, "%s\t", opcode->name); + info->print_address_func((bfd_vma) imm, info); + length = 6; + } + break; + case MOXIE_F1_AiB: + fpr (stream, "%s\t(%s), %s", opcode->name, + reg_names[OP_A(iword)], reg_names[OP_B(iword)]); + break; + case MOXIE_F1_ABi: + fpr(stream, "%s\t%s, (%s)", opcode->name, + reg_names[OP_A(iword)], reg_names[OP_B(iword)]); + break; + case MOXIE_F1_4A: + { + unsigned imm; + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) + goto fail; + imm = bfd_getb32(buffer); + fpr(stream, "%s\t0x%x, %s", + opcode->name, imm, reg_names[OP_A(iword)]); + length = 6; + } + break; + case MOXIE_F1_AiB4: + { + unsigned imm; + if ((status = info->read_memory_func(addr+2, buffer, 4, info))) + goto fail; + imm = bfd_getb32(buffer); + fpr(stream, "%s\t0x%x(%s), %s", opcode->name, + imm, + reg_names[OP_A(iword)], + reg_names[OP_B(iword)]); + length = 6; + } + break; + case MOXIE_F1_ABi4: + { + unsigned imm; + if ((status = info->read_memory_func(addr+2, buffer, 4, info))) + goto fail; + imm = bfd_getb32(buffer); + fpr(stream, "%s\t%s, 0x%x(%s)", + opcode->name, + reg_names[OP_A(iword)], + imm, + reg_names[OP_B(iword)]); + length = 6; + } + break; + default: + abort(); + } + } + else if ((iword & (1<<14)) == 0) { + /* Extract the Form 2 opcode. */ + opcode = &moxie_form2_opc_info[(iword >> 12) & 3]; + switch (opcode->itype) { + case MOXIE_F2_A8V: + fpr(stream, "%s\t%s, 0x%x", + opcode->name, + reg_names[(iword >> 8) & 0xf], + iword & ((1 << 8) - 1)); + break; + case MOXIE_F2_NARG: + fpr(stream, "%s", opcode->name); + break; + default: + abort(); + } + } else { + /* Extract the Form 3 opcode. */ + opcode = &moxie_form3_opc_info[(iword >> 10) & 15]; + switch (opcode->itype) { + case MOXIE_F3_PCREL: + fpr(stream, "%s\t", opcode->name); + info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2), + info); + break; + default: + abort(); + } + } + + return length; + + fail: + info->memory_error_func(status, addr, info); + return -1; +} diff --git a/include/disas/bfd.h b/include/disas/bfd.h index 3944b3c..196b792 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -188,20 +188,20 @@ enum bfd_architecture #define bfd_mach_alpha_ev5 0x20 #define bfd_mach_alpha_ev6 0x30 bfd_arch_arm, /* Advanced Risc Machines ARM */ -#define bfd_mach_arm_unknown 0 -#define bfd_mach_arm_2 1 -#define bfd_mach_arm_2a 2 -#define bfd_mach_arm_3 3 -#define bfd_mach_arm_3M 4 -#define bfd_mach_arm_4 5 -#define bfd_mach_arm_4T 6 -#define bfd_mach_arm_5 7 -#define bfd_mach_arm_5T 8 -#define bfd_mach_arm_5TE 9 -#define bfd_mach_arm_XScale 10 -#define bfd_mach_arm_ep9312 11 -#define bfd_mach_arm_iWMMXt 12 -#define bfd_mach_arm_iWMMXt2 13 +#define bfd_mach_arm_unknown 0 +#define bfd_mach_arm_2 1 +#define bfd_mach_arm_2a 2 +#define bfd_mach_arm_3 3 +#define bfd_mach_arm_3M 4 +#define bfd_mach_arm_4 5 +#define bfd_mach_arm_4T 6 +#define bfd_mach_arm_5 7 +#define bfd_mach_arm_5T 8 +#define bfd_mach_arm_5TE 9 +#define bfd_mach_arm_XScale 10 +#define bfd_mach_arm_ep9312 11 +#define bfd_mach_arm_iWMMXt 12 +#define bfd_mach_arm_iWMMXt2 13 bfd_arch_ns32k, /* National Semiconductors ns32000 */ bfd_arch_w65, /* WDC 65816 */ bfd_arch_tic30, /* Texas Instruments TMS320C30 */ @@ -218,6 +218,7 @@ enum bfd_architecture #define bfd_mach_cris_v32 32 #define bfd_mach_cris_v10_v32 1032 bfd_arch_microblaze, /* Xilinx MicroBlaze. */ + bfd_arch_moxie, /* The Moxie core. */ bfd_arch_ia64, /* HP/Intel ia64 */ #define bfd_mach_ia64_elf64 64 #define bfd_mach_ia64_elf32 32 @@ -239,14 +240,14 @@ typedef struct symbol_cache_entry } asymbol; enum dis_insn_type { - dis_noninsn, /* Not a valid instruction */ - dis_nonbranch, /* Not a branch instruction */ - dis_branch, /* Unconditional branch */ - dis_condbranch, /* Conditional branch */ - dis_jsr, /* Jump to subroutine */ - dis_condjsr, /* Conditional jump to subroutine */ - dis_dref, /* Data reference instruction */ - dis_dref2 /* Two data references in instruction */ + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ }; /* This struct is passed into the instruction decoding routine, @@ -289,7 +290,7 @@ typedef struct disassemble_info { The top 16 bits are reserved for public use (and are documented here). The bottom 16 bits are for the internal use of the disassembler. */ unsigned long flags; -#define INSN_HAS_RELOC 0x80000000 +#define INSN_HAS_RELOC 0x80000000 PTR private_data; /* Function used to get bytes to disassemble. MEMADDR is the @@ -299,7 +300,7 @@ typedef struct disassemble_info { Returns an errno value or 0 for success. */ int (*read_memory_func) (bfd_vma memaddr, bfd_byte *myaddr, int length, - struct disassemble_info *info); + struct disassemble_info *info); /* Function which should be called if we get an error that we can't recover from. STATUS is the errno value from read_memory_func and @@ -348,14 +349,14 @@ typedef struct disassemble_info { To determine whether this decoder supports this information, set insn_info_valid to 0, decode an instruction, then check it. */ - char insn_info_valid; /* Branch info has been set. */ - char branch_delay_insns; /* How many sequential insn's will run before - a branch takes effect. (0 = normal) */ - char data_size; /* Size of data reference in insn, in bytes */ - enum dis_insn_type insn_type; /* Type of instruction */ - bfd_vma target; /* Target address of branch or dref, if known; - zero if unknown. */ - bfd_vma target2; /* Second target address for dref2 */ + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ /* Command line options specific to the target disassembler. */ char * disassembler_options; @@ -392,6 +393,7 @@ int print_insn_m32r (bfd_vma, disassemble_info*); int print_insn_m88k (bfd_vma, disassemble_info*); int print_insn_mn10200 (bfd_vma, disassemble_info*); int print_insn_mn10300 (bfd_vma, disassemble_info*); +int print_insn_moxie (bfd_vma, disassemble_info*); int print_insn_ns32k (bfd_vma, disassemble_info*); int print_insn_big_powerpc (bfd_vma, disassemble_info*); int print_insn_little_powerpc (bfd_vma, disassemble_info*); -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH v7 2/4] Add moxie disassembler 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 2/4] Add moxie disassembler Anthony Green @ 2013-03-03 15:52 ` Blue Swirl 0 siblings, 0 replies; 8+ messages in thread From: Blue Swirl @ 2013-03-03 15:52 UTC (permalink / raw) To: Anthony Green; +Cc: qemu-devel On Sun, Mar 3, 2013 at 1:07 PM, Anthony Green <green@moxielogic.com> wrote: > > Signed-off-by: Anthony Green <green@moxielogic.com> > --- > disas.c | 6 + > disas/Makefile.objs | 1 + > disas/moxie.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/disas/bfd.h | 66 +++++----- > 4 files changed, 401 insertions(+), 32 deletions(-) > create mode 100644 disas/moxie.c > > diff --git a/disas.c b/disas.c > index a46faee..74d3ba0 100644 > --- a/disas.c > +++ b/disas.c > @@ -256,6 +256,9 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code, > #elif defined(TARGET_MICROBLAZE) > s.info.mach = bfd_arch_microblaze; > print_insn = print_insn_microblaze; > +#elif defined(TARGET_MOXIE) > + s.info.mach = bfd_arch_moxie; > + print_insn = print_insn_moxie; > #elif defined(TARGET_LM32) > s.info.mach = bfd_mach_lm32; > print_insn = print_insn_lm32; > @@ -462,6 +465,9 @@ void monitor_disas(Monitor *mon, CPUArchState *env, > #elif defined(TARGET_S390X) > s.info.mach = bfd_mach_s390_64; > print_insn = print_insn_s390; > +#elif defined(TARGET_MOXIE) > + s.info.mach = bfd_arch_moxie; > + print_insn = print_insn_moxie; > #elif defined(TARGET_LM32) > s.info.mach = bfd_mach_lm32; > print_insn = print_insn_lm32; > diff --git a/disas/Makefile.objs b/disas/Makefile.objs > index ed75f9a..3b1e77a 100644 > --- a/disas/Makefile.objs > +++ b/disas/Makefile.objs > @@ -7,6 +7,7 @@ common-obj-$(CONFIG_IA64_DIS) += ia64.o > common-obj-$(CONFIG_M68K_DIS) += m68k.o > common-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o > common-obj-$(CONFIG_MIPS_DIS) += mips.o > +common-obj-$(CONFIG_MOXIE_DIS) += moxie.o > common-obj-$(CONFIG_PPC_DIS) += ppc.o > common-obj-$(CONFIG_S390_DIS) += s390.o > common-obj-$(CONFIG_SH4_DIS) += sh4.o > diff --git a/disas/moxie.c b/disas/moxie.c > new file mode 100644 > index 0000000..4c5f180 > --- /dev/null > +++ b/disas/moxie.c > @@ -0,0 +1,360 @@ > +/* Disassemble moxie instructions. > + Copyright (c) 2009 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 2 of the License, or > + (at your option) any later version. > + > + This program 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 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> > +#define STATIC_TABLE > +#define DEFINE_TABLE > + > +#include "disas/bfd.h" > + > +static void *stream; > + > +/* Form 1 instructions come in different flavors: > + > + Some have no arguments (MOXIE_F1_NARG) > + Some only use the A operand (MOXIE_F1_A) > + Some use A and B registers (MOXIE_F1_AB) > + Some use A and consume a 4 byte immediate value (MOXIE_F1_A4) > + Some use just a 4 byte immediate value (MOXIE_F1_4) > + Some use just a 4 byte memory address (MOXIE_F1_M) > + Some use B and an indirect A (MOXIE_F1_AiB) > + Some use A and an indirect B (MOXIE_F1_ABi) > + Some consume a 4 byte immediate value and use X (MOXIE_F1_4A) > + Some use B and an indirect A plus 4 bytes (MOXIE_F1_AiB4) > + Some use A and an indirect B plus 4 bytes (MOXIE_F1_ABi4) > + > + Form 2 instructions also come in different flavors: > + > + Some have no arguments (MOXIE_F2_NARG) > + Some use the A register and an 8-bit value (MOXIE_F2_A8V) > + > + Form 3 instructions also come in different flavors: > + > + Some have no arguments (MOXIE_F3_NARG) > + Some have a 10-bit PC relative operand (MOXIE_F3_PCREL). */ > + > +#define MOXIE_F1_NARG 0x100 > +#define MOXIE_F1_A 0x101 > +#define MOXIE_F1_AB 0x102 > +/* #define MOXIE_F1_ABC 0x103 */ > +#define MOXIE_F1_A4 0x104 > +#define MOXIE_F1_4 0x105 > +#define MOXIE_F1_AiB 0x106 > +#define MOXIE_F1_ABi 0x107 > +#define MOXIE_F1_4A 0x108 > +#define MOXIE_F1_AiB4 0x109 > +#define MOXIE_F1_ABi4 0x10a > +#define MOXIE_F1_M 0x10b > + > +#define MOXIE_F2_NARG 0x200 > +#define MOXIE_F2_A8V 0x201 > + > +#define MOXIE_F3_NARG 0x300 > +#define MOXIE_F3_PCREL 0x301 > + > +typedef struct moxie_opc_info_t { > + short opcode; > + unsigned itype; > + const char * name; > +} moxie_opc_info_t; > + > +extern const moxie_opc_info_t moxie_form1_opc_info[64]; > +extern const moxie_opc_info_t moxie_form2_opc_info[4]; > +extern const moxie_opc_info_t moxie_form3_opc_info[16]; > + > +/* The moxie processor's 16-bit instructions come in two forms: > + > + FORM 1 instructions start with a 0 bit... > + > + 0oooooooaaaabbbb > + 0 F > + > + ooooooo - form 1 opcode number > + aaaa - operand A > + bbbb - operand B > + > + FORM 2 instructions start with bits "10"... > + > + 10ooaaaavvvvvvvv > + 0 F > + > + oo - form 2 opcode number > + aaaa - operand A > + vvvvvvvv - 8-bit immediate value > + > + FORM 3 instructions start with a bits "11"... > + > + 11oooovvvvvvvvvv > + 0 F > + > + oooo - form 3 opcode number > + vvvvvvvvvv - 10-bit immediate value. */ > + > +const moxie_opc_info_t moxie_form1_opc_info[64] = > + { > + { 0x00, MOXIE_F1_NARG, "nop" }, > + { 0x01, MOXIE_F1_A4, "ldi.l" }, > + { 0x02, MOXIE_F1_AB, "mov" }, > + { 0x03, MOXIE_F1_M, "jsra" }, > + { 0x04, MOXIE_F1_NARG, "ret" }, > + { 0x05, MOXIE_F1_AB, "add.l" }, > + { 0x06, MOXIE_F1_AB, "push" }, > + { 0x07, MOXIE_F1_AB, "pop" }, > + { 0x08, MOXIE_F1_A4, "lda.l" }, > + { 0x09, MOXIE_F1_4A, "sta.l" }, > + { 0x0a, MOXIE_F1_ABi, "ld.l" }, > + { 0x0b, MOXIE_F1_AiB, "st.l" }, > + { 0x0c, MOXIE_F1_ABi4, "ldo.l" }, > + { 0x0d, MOXIE_F1_AiB4, "sto.l" }, > + { 0x0e, MOXIE_F1_AB, "cmp" }, > + { 0x0f, MOXIE_F1_NARG, "bad" }, > + { 0x10, MOXIE_F1_NARG, "bad" }, > + { 0x11, MOXIE_F1_NARG, "bad" }, > + { 0x12, MOXIE_F1_NARG, "bad" }, > + { 0x13, MOXIE_F1_NARG, "bad" }, > + { 0x14, MOXIE_F1_NARG, "bad" }, > + { 0x15, MOXIE_F1_NARG, "bad" }, > + { 0x16, MOXIE_F1_NARG, "bad" }, > + { 0x17, MOXIE_F1_NARG, "bad" }, > + { 0x18, MOXIE_F1_NARG, "bad" }, > + { 0x19, MOXIE_F1_A, "jsr" }, > + { 0x1a, MOXIE_F1_M, "jmpa" }, > + { 0x1b, MOXIE_F1_A4, "ldi.b" }, > + { 0x1c, MOXIE_F1_ABi, "ld.b" }, > + { 0x1d, MOXIE_F1_A4, "lda.b" }, > + { 0x1e, MOXIE_F1_AiB, "st.b" }, > + { 0x1f, MOXIE_F1_4A, "sta.b" }, > + { 0x20, MOXIE_F1_A4, "ldi.s" }, > + { 0x21, MOXIE_F1_ABi, "ld.s" }, > + { 0x22, MOXIE_F1_A4, "lda.s" }, > + { 0x23, MOXIE_F1_AiB, "st.s" }, > + { 0x24, MOXIE_F1_4A, "sta.s" }, > + { 0x25, MOXIE_F1_A, "jmp" }, > + { 0x26, MOXIE_F1_AB, "and" }, > + { 0x27, MOXIE_F1_AB, "lshr" }, > + { 0x28, MOXIE_F1_AB, "ashl" }, > + { 0x29, MOXIE_F1_AB, "sub.l" }, > + { 0x2a, MOXIE_F1_AB, "neg" }, > + { 0x2b, MOXIE_F1_AB, "or" }, > + { 0x2c, MOXIE_F1_AB, "not" }, > + { 0x2d, MOXIE_F1_AB, "ashr" }, > + { 0x2e, MOXIE_F1_AB, "xor" }, > + { 0x2f, MOXIE_F1_AB, "mul.l" }, > + { 0x30, MOXIE_F1_4, "swi" }, > + { 0x31, MOXIE_F1_AB, "div.l" }, > + { 0x32, MOXIE_F1_AB, "udiv.l" }, > + { 0x33, MOXIE_F1_AB, "mod.l" }, > + { 0x34, MOXIE_F1_AB, "umod.l" }, > + { 0x35, MOXIE_F1_NARG, "brk" }, > + { 0x36, MOXIE_F1_ABi4, "ldo.b" }, > + { 0x37, MOXIE_F1_AiB4, "sto.b" }, > + { 0x38, MOXIE_F1_ABi4, "ldo.s" }, > + { 0x39, MOXIE_F1_AiB4, "sto.s" }, > + { 0x3a, MOXIE_F1_NARG, "bad" }, > + { 0x3b, MOXIE_F1_NARG, "bad" }, > + { 0x3c, MOXIE_F1_NARG, "bad" }, > + { 0x3d, MOXIE_F1_NARG, "bad" }, > + { 0x3e, MOXIE_F1_NARG, "bad" }, > + { 0x3f, MOXIE_F1_NARG, "bad" } > + }; > + > +const moxie_opc_info_t moxie_form2_opc_info[4] = > + { > + { 0x00, MOXIE_F2_A8V, "inc" }, > + { 0x01, MOXIE_F2_A8V, "dec" }, > + { 0x02, MOXIE_F2_A8V, "gsr" }, > + { 0x03, MOXIE_F2_A8V, "ssr" } > + }; > + > +const moxie_opc_info_t moxie_form3_opc_info[16] = > + { > + { 0x00, MOXIE_F3_PCREL,"beq" }, > + { 0x01, MOXIE_F3_PCREL,"bne" }, > + { 0x02, MOXIE_F3_PCREL,"blt" }, > + { 0x03, MOXIE_F3_PCREL,"bgt" }, > + { 0x04, MOXIE_F3_PCREL,"bltu" }, > + { 0x05, MOXIE_F3_PCREL,"bgtu" }, > + { 0x06, MOXIE_F3_PCREL,"bge" }, > + { 0x07, MOXIE_F3_PCREL,"ble" }, > + { 0x08, MOXIE_F3_PCREL,"bgeu" }, > + { 0x09, MOXIE_F3_PCREL,"bleu" }, > + { 0x0a, MOXIE_F3_NARG, "bad" }, > + { 0x0b, MOXIE_F3_NARG, "bad" }, > + { 0x0c, MOXIE_F3_NARG, "bad" }, > + { 0x0d, MOXIE_F3_NARG, "bad" }, > + { 0x0e, MOXIE_F3_NARG, "bad" }, > + { 0x0f, MOXIE_F3_NARG, "bad" } > + }; > + > +/* Macros to extract operands from the instruction word. */ > +#define OP_A(i) ((i >> 4) & 0xf) > +#define OP_B(i) (i & 0xf) > +#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1) > + > +static const char * reg_names[16] = > + { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", > + "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" }; > + > +int > +print_insn_moxie(bfd_vma addr, struct disassemble_info * info) > +{ > + int length = 2; > + int status; > + stream = info->stream; > + const moxie_opc_info_t * opcode; > + bfd_byte buffer[4]; > + unsigned short iword; > + fprintf_function fpr = info->fprintf_func; > + > + if ((status = info->read_memory_func(addr, buffer, 2, info))) > + goto fail; > + iword = (bfd_getb16(buffer) >> 16); > + > + /* Form 1 instructions have the high bit set to 0. */ > + if ((iword & (1<<15)) == 0) { > + /* Extract the Form 1 opcode. */ > + opcode = &moxie_form1_opc_info[iword >> 8]; > + switch (opcode->itype) { > + case MOXIE_F1_NARG: > + fpr(stream, "%s", opcode->name); > + break; > + case MOXIE_F1_A: > + fpr(stream, "%s\t%s", opcode->name, > + reg_names[OP_A(iword)]); > + break; > + case MOXIE_F1_AB: > + fpr(stream, "%s\t%s, %s", opcode->name, > + reg_names[OP_A(iword)], > + reg_names[OP_B(iword)]); > + break; > + case MOXIE_F1_A4: > + { > + unsigned imm; > + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) > + goto fail; > + imm = bfd_getb32(buffer); > + fpr(stream, "%s\t%s, 0x%x", opcode->name, > + reg_names[OP_A(iword)], imm); > + length = 6; > + } > + break; > + case MOXIE_F1_4: > + { > + unsigned imm; > + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) > + goto fail; > + imm = bfd_getb32(buffer); > + fpr(stream, "%s\t0x%x", opcode->name, imm); > + length = 6; > + } > + break; > + case MOXIE_F1_M: > + { > + unsigned imm; > + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) > + goto fail; > + imm = bfd_getb32(buffer); > + fpr(stream, "%s\t", opcode->name); > + info->print_address_func((bfd_vma) imm, info); > + length = 6; > + } > + break; > + case MOXIE_F1_AiB: > + fpr (stream, "%s\t(%s), %s", opcode->name, > + reg_names[OP_A(iword)], reg_names[OP_B(iword)]); > + break; > + case MOXIE_F1_ABi: > + fpr(stream, "%s\t%s, (%s)", opcode->name, > + reg_names[OP_A(iword)], reg_names[OP_B(iword)]); > + break; > + case MOXIE_F1_4A: > + { > + unsigned imm; > + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) > + goto fail; > + imm = bfd_getb32(buffer); > + fpr(stream, "%s\t0x%x, %s", > + opcode->name, imm, reg_names[OP_A(iword)]); > + length = 6; > + } > + break; > + case MOXIE_F1_AiB4: > + { > + unsigned imm; > + if ((status = info->read_memory_func(addr+2, buffer, 4, info))) > + goto fail; > + imm = bfd_getb32(buffer); > + fpr(stream, "%s\t0x%x(%s), %s", opcode->name, > + imm, > + reg_names[OP_A(iword)], > + reg_names[OP_B(iword)]); > + length = 6; > + } > + break; > + case MOXIE_F1_ABi4: > + { > + unsigned imm; > + if ((status = info->read_memory_func(addr+2, buffer, 4, info))) > + goto fail; > + imm = bfd_getb32(buffer); > + fpr(stream, "%s\t%s, 0x%x(%s)", > + opcode->name, > + reg_names[OP_A(iword)], > + imm, > + reg_names[OP_B(iword)]); > + length = 6; > + } > + break; > + default: > + abort(); > + } > + } > + else if ((iword & (1<<14)) == 0) { > + /* Extract the Form 2 opcode. */ > + opcode = &moxie_form2_opc_info[(iword >> 12) & 3]; > + switch (opcode->itype) { > + case MOXIE_F2_A8V: > + fpr(stream, "%s\t%s, 0x%x", > + opcode->name, > + reg_names[(iword >> 8) & 0xf], > + iword & ((1 << 8) - 1)); > + break; > + case MOXIE_F2_NARG: > + fpr(stream, "%s", opcode->name); > + break; > + default: > + abort(); > + } > + } else { > + /* Extract the Form 3 opcode. */ > + opcode = &moxie_form3_opc_info[(iword >> 10) & 15]; > + switch (opcode->itype) { > + case MOXIE_F3_PCREL: > + fpr(stream, "%s\t", opcode->name); > + info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2), > + info); > + break; > + default: > + abort(); > + } > + } > + > + return length; > + > + fail: > + info->memory_error_func(status, addr, info); > + return -1; > +} > diff --git a/include/disas/bfd.h b/include/disas/bfd.h > index 3944b3c..196b792 100644 > --- a/include/disas/bfd.h > +++ b/include/disas/bfd.h > @@ -188,20 +188,20 @@ enum bfd_architecture > #define bfd_mach_alpha_ev5 0x20 > #define bfd_mach_alpha_ev6 0x30 > bfd_arch_arm, /* Advanced Risc Machines ARM */ > -#define bfd_mach_arm_unknown 0 > -#define bfd_mach_arm_2 1 > -#define bfd_mach_arm_2a 2 > -#define bfd_mach_arm_3 3 > -#define bfd_mach_arm_3M 4 > -#define bfd_mach_arm_4 5 > -#define bfd_mach_arm_4T 6 > -#define bfd_mach_arm_5 7 > -#define bfd_mach_arm_5T 8 > -#define bfd_mach_arm_5TE 9 > -#define bfd_mach_arm_XScale 10 > -#define bfd_mach_arm_ep9312 11 > -#define bfd_mach_arm_iWMMXt 12 > -#define bfd_mach_arm_iWMMXt2 13 > +#define bfd_mach_arm_unknown 0 > +#define bfd_mach_arm_2 1 > +#define bfd_mach_arm_2a 2 > +#define bfd_mach_arm_3 3 > +#define bfd_mach_arm_3M 4 > +#define bfd_mach_arm_4 5 > +#define bfd_mach_arm_4T 6 > +#define bfd_mach_arm_5 7 > +#define bfd_mach_arm_5T 8 > +#define bfd_mach_arm_5TE 9 > +#define bfd_mach_arm_XScale 10 > +#define bfd_mach_arm_ep9312 11 > +#define bfd_mach_arm_iWMMXt 12 > +#define bfd_mach_arm_iWMMXt2 13 Now these unrelated changes are back again. > bfd_arch_ns32k, /* National Semiconductors ns32000 */ > bfd_arch_w65, /* WDC 65816 */ > bfd_arch_tic30, /* Texas Instruments TMS320C30 */ > @@ -218,6 +218,7 @@ enum bfd_architecture > #define bfd_mach_cris_v32 32 > #define bfd_mach_cris_v10_v32 1032 > bfd_arch_microblaze, /* Xilinx MicroBlaze. */ > + bfd_arch_moxie, /* The Moxie core. */ > bfd_arch_ia64, /* HP/Intel ia64 */ > #define bfd_mach_ia64_elf64 64 > #define bfd_mach_ia64_elf32 32 > @@ -239,14 +240,14 @@ typedef struct symbol_cache_entry > } asymbol; > > enum dis_insn_type { > - dis_noninsn, /* Not a valid instruction */ > - dis_nonbranch, /* Not a branch instruction */ > - dis_branch, /* Unconditional branch */ > - dis_condbranch, /* Conditional branch */ > - dis_jsr, /* Jump to subroutine */ > - dis_condjsr, /* Conditional jump to subroutine */ > - dis_dref, /* Data reference instruction */ > - dis_dref2 /* Two data references in instruction */ > + dis_noninsn, /* Not a valid instruction */ > + dis_nonbranch, /* Not a branch instruction */ > + dis_branch, /* Unconditional branch */ > + dis_condbranch, /* Conditional branch */ > + dis_jsr, /* Jump to subroutine */ > + dis_condjsr, /* Conditional jump to subroutine */ > + dis_dref, /* Data reference instruction */ > + dis_dref2 /* Two data references in instruction */ > }; > > /* This struct is passed into the instruction decoding routine, > @@ -289,7 +290,7 @@ typedef struct disassemble_info { > The top 16 bits are reserved for public use (and are documented here). > The bottom 16 bits are for the internal use of the disassembler. */ > unsigned long flags; > -#define INSN_HAS_RELOC 0x80000000 > +#define INSN_HAS_RELOC 0x80000000 > PTR private_data; > > /* Function used to get bytes to disassemble. MEMADDR is the > @@ -299,7 +300,7 @@ typedef struct disassemble_info { > Returns an errno value or 0 for success. */ > int (*read_memory_func) > (bfd_vma memaddr, bfd_byte *myaddr, int length, > - struct disassemble_info *info); > + struct disassemble_info *info); > > /* Function which should be called if we get an error that we can't > recover from. STATUS is the errno value from read_memory_func and > @@ -348,14 +349,14 @@ typedef struct disassemble_info { > To determine whether this decoder supports this information, set > insn_info_valid to 0, decode an instruction, then check it. */ > > - char insn_info_valid; /* Branch info has been set. */ > - char branch_delay_insns; /* How many sequential insn's will run before > - a branch takes effect. (0 = normal) */ > - char data_size; /* Size of data reference in insn, in bytes */ > - enum dis_insn_type insn_type; /* Type of instruction */ > - bfd_vma target; /* Target address of branch or dref, if known; > - zero if unknown. */ > - bfd_vma target2; /* Second target address for dref2 */ > + char insn_info_valid; /* Branch info has been set. */ > + char branch_delay_insns; /* How many sequential insn's will run before > + a branch takes effect. (0 = normal) */ > + char data_size; /* Size of data reference in insn, in bytes */ > + enum dis_insn_type insn_type; /* Type of instruction */ > + bfd_vma target; /* Target address of branch or dref, if known; > + zero if unknown. */ > + bfd_vma target2; /* Second target address for dref2 */ > > /* Command line options specific to the target disassembler. */ > char * disassembler_options; > @@ -392,6 +393,7 @@ int print_insn_m32r (bfd_vma, disassemble_info*); > int print_insn_m88k (bfd_vma, disassemble_info*); > int print_insn_mn10200 (bfd_vma, disassemble_info*); > int print_insn_mn10300 (bfd_vma, disassemble_info*); > +int print_insn_moxie (bfd_vma, disassemble_info*); > int print_insn_ns32k (bfd_vma, disassemble_info*); > int print_insn_big_powerpc (bfd_vma, disassemble_info*); > int print_insn_little_powerpc (bfd_vma, disassemble_info*); > -- > 1.8.1.4 > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v7 3/4] Add sample moxie system 2013-03-03 13:07 [Qemu-devel] [PATCH v7 0/4] Moxie CPU port Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 1/4] Add moxie target code Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 2/4] Add moxie disassembler Anthony Green @ 2013-03-03 13:07 ` Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 4/4] Add top level changes for moxie Anthony Green 3 siblings, 0 replies; 8+ messages in thread From: Anthony Green @ 2013-03-03 13:07 UTC (permalink / raw) To: qemu-devel; +Cc: Anthony Green Signed-off-by: Anthony Green <green@moxielogic.com> --- hw/moxie/Makefile.objs | 6 ++ hw/moxie/moxiesim.c | 174 +++++++++++++++++++++++++++++++++++++++++++++ include/sysemu/arch_init.h | 1 + 3 files changed, 181 insertions(+) create mode 100644 hw/moxie/Makefile.objs create mode 100644 hw/moxie/moxiesim.c diff --git a/hw/moxie/Makefile.objs b/hw/moxie/Makefile.objs new file mode 100644 index 0000000..d0772d1 --- /dev/null +++ b/hw/moxie/Makefile.objs @@ -0,0 +1,6 @@ +# moxie boards +obj-y = serial.o mc146818rtc.o vga.o +obj-$(CONFIG_FDT) += device_tree.o + +obj-y := $(addprefix ../,$(obj-y)) +obj-y += moxiesim.o diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c new file mode 100644 index 0000000..e1e88a9 --- /dev/null +++ b/hw/moxie/moxiesim.c @@ -0,0 +1,174 @@ +/* + * QEMU/moxiesim emulation + * + * Emulates a very simple machine model similiar to the one use by the + * GDB moxie simulator. + * + * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/serial.h" +#include "exec/address-spaces.h" + +#define PHYS_MEM_BASE 0x80000000 + +typedef struct { + uint64_t ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} LoaderParams; + +static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) +{ + uint64_t entry, kernel_low, kernel_high; + long kernel_size; + long initrd_size; + ram_addr_t initrd_offset; + + kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL, + &entry, &kernel_low, &kernel_high, 1, + ELF_MACHINE, 0); + + if (!kernel_size) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + loader_params->kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + initrd_offset = 0; + if (loader_params->initrd_filename) { + initrd_size = get_image_size(loader_params->initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) + & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > loader_params->ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + loader_params->initrd_filename); + exit(1); + } + initrd_size = load_image_targphys(loader_params->initrd_filename, + initrd_offset, + ram_size); + } + if (initrd_size == (target_ulong)-1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + loader_params->initrd_filename); + exit(1); + } + } +} + +static void main_cpu_reset(void *opaque) +{ + MoxieCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static inline DeviceState * +moxie_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "moxie,intc"); + qdev_prop_set_uint32(dev, "kind-of-intr", kind_of_intr); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); + return dev; +} + +static void moxiesim_init(QEMUMachineInitArgs *args) +{ + MoxieCPU *cpu = NULL; + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + CPUMoxieState *env; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + MemoryRegion *rom = g_new(MemoryRegion, 1); + hwaddr ram_base = 0x200000; + LoaderParams loader_params; + + /* Init CPUs. */ + if (cpu_model == NULL) { + cpu_model = "MoxieLite-moxie-cpu"; + } + cpu = cpu_moxie_init(cpu_model); + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + env = &cpu->env; + + qemu_register_reset(main_cpu_reset, cpu); + + /* Allocate RAM. */ + memory_region_init_ram(ram, "moxiesim.ram", ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(address_space_mem, ram_base, ram); + + memory_region_init_ram(rom, "moxie.rom", 128*0x1000); + vmstate_register_ram_global(rom); + memory_region_add_subregion(get_system_memory(), 0x1000, rom); + + if (kernel_filename) { + loader_params.ram_size = ram_size; + loader_params.kernel_filename = kernel_filename; + loader_params.kernel_cmdline = kernel_cmdline; + loader_params.initrd_filename = initrd_filename; + load_kernel(cpu, &loader_params); + } + + /* A single 16450 sits at offset 0x3f8. */ + if (serial_hds[0]) { + serial_mm_init(address_space_mem, 0x3f8, 0, env->irq[4], + 8000000/16, serial_hds[0], DEVICE_LITTLE_ENDIAN); + } +} + +static QEMUMachine moxiesim_machine = { + .name = "moxiesim", + .desc = "Moxie simulator platform", + .init = moxiesim_init, + .is_default = 1, +}; + +static void moxie_machine_init(void) +{ + qemu_register_machine(&moxiesim_machine); +} + +machine_init(moxie_machine_init) diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 5fc780c..8c8d78e 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -20,6 +20,7 @@ enum { QEMU_ARCH_XTENSA = 4096, QEMU_ARCH_OPENRISC = 8192, QEMU_ARCH_UNICORE32 = 0x4000, + QEMU_ARCH_MOXIE = 0x8000, }; extern const uint32_t arch_type; -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH v7 4/4] Add top level changes for moxie 2013-03-03 13:07 [Qemu-devel] [PATCH v7 0/4] Moxie CPU port Anthony Green ` (2 preceding siblings ...) 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 3/4] Add sample moxie system Anthony Green @ 2013-03-03 13:07 ` Anthony Green 3 siblings, 0 replies; 8+ messages in thread From: Anthony Green @ 2013-03-03 13:07 UTC (permalink / raw) To: qemu-devel; +Cc: Anthony Green Signed-off-by: Anthony Green <green@moxielogic.com> --- MAINTAINERS | 5 +++++ arch_init.c | 2 ++ configure | 9 ++++++++- cpu-exec.c | 2 ++ default-configs/moxie-softmmu.mak | 2 ++ qapi-schema.json | 6 +++--- 6 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 default-configs/moxie-softmmu.mak diff --git a/MAINTAINERS b/MAINTAINERS index 21043e4..b970159 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -91,6 +91,11 @@ M: Aurelien Jarno <aurelien@aurel32.net> S: Odd Fixes F: target-mips/ +Moxie +M: Anthony Green <green@moxielogic.com> +S: Maintained +F: target-moxie/ + PowerPC M: Alexander Graf <agraf@suse.de> L: qemu-ppc@nongnu.org diff --git a/arch_init.c b/arch_init.c index 8daeafa..ddae1b7 100644 --- a/arch_init.c +++ b/arch_init.c @@ -85,6 +85,8 @@ int graphic_depth = 15; #define QEMU_ARCH QEMU_ARCH_MICROBLAZE #elif defined(TARGET_MIPS) #define QEMU_ARCH QEMU_ARCH_MIPS +#elif defined(TARGET_MOXIE) +#define QEMU_ARCH QEMU_ARCH_MOXIE #elif defined(TARGET_OPENRISC) #define QEMU_ARCH QEMU_ARCH_OPENRISC #elif defined(TARGET_PPC) diff --git a/configure b/configure index 19738ac..ae5b3bc 100755 --- a/configure +++ b/configure @@ -958,6 +958,7 @@ mips-softmmu \ mipsel-softmmu \ mips64-softmmu \ mips64el-softmmu \ +moxie-softmmu \ or32-softmmu \ ppc-softmmu \ ppcemb-softmmu \ @@ -3913,7 +3914,7 @@ target_arch2=`echo $target | cut -d '-' -f 1` target_bigendian="no" case "$target_arch2" in - armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -4018,6 +4019,8 @@ case "$target_arch2" in echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak target_long_alignment=8 ;; + moxie) + ;; or32) TARGET_ARCH=openrisc TARGET_BASE_ARCH=openrisc @@ -4262,6 +4265,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do echo "CONFIG_MIPS_DIS=y" >> $config_target_mak echo "CONFIG_MIPS_DIS=y" >> config-all-disas.mak ;; + moxie*) + echo "CONFIG_MOXIE_DIS=y" >> $config_target_mak + echo "CONFIG_MOXIE_DIS=y" >> config-all-disas.mak + ;; or32) echo "CONFIG_OPENRISC_DIS=y" >> $config_target_mak echo "CONFIG_OPENRISC_DIS=y" >> config-all-disas.mak diff --git a/cpu-exec.c b/cpu-exec.c index afbe497..ba7ea41 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -221,6 +221,7 @@ int cpu_exec(CPUArchState *env) #elif defined(TARGET_LM32) #elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) +#elif defined(TARGET_MOXIE) #elif defined(TARGET_OPENRISC) #elif defined(TARGET_SH4) #elif defined(TARGET_CRIS) @@ -655,6 +656,7 @@ int cpu_exec(CPUArchState *env) | env->cc_dest | (env->cc_x << 4); #elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) +#elif defined(TARGET_MOXIE) #elif defined(TARGET_OPENRISC) #elif defined(TARGET_SH4) #elif defined(TARGET_ALPHA) diff --git a/default-configs/moxie-softmmu.mak b/default-configs/moxie-softmmu.mak new file mode 100644 index 0000000..d378363 --- /dev/null +++ b/default-configs/moxie-softmmu.mak @@ -0,0 +1,2 @@ +# Default configuration for moxie-softmmu + diff --git a/qapi-schema.json b/qapi-schema.json index 28b070f..233ea1b 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2994,9 +2994,9 @@ ## { 'enum': 'TargetType', 'data': [ 'alpha', 'arm', 'cris', 'i386', 'lm32', 'm68k', 'microblazeel', - 'microblaze', 'mips64el', 'mips64', 'mipsel', 'mips', 'or32', - 'ppc64', 'ppcemb', 'ppc', 's390x', 'sh4eb', 'sh4', 'sparc64', - 'sparc', 'unicore32', 'x86_64', 'xtensaeb', 'xtensa' ] } + 'microblaze', 'mips64el', 'mips64', 'mipsel', 'mips', 'moxie', + 'or32', 'ppc64', 'ppcemb', 'ppc', 's390x', 'sh4eb', 'sh4', + 'sparc64', 'sparc', 'unicore32', 'x86_64', 'xtensaeb', 'xtensa' ] } ## # @TargetInfo: -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2013-03-03 22:10 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-03-03 13:07 [Qemu-devel] [PATCH v7 0/4] Moxie CPU port Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 1/4] Add moxie target code Anthony Green 2013-03-03 16:15 ` Blue Swirl 2013-03-03 22:09 ` Peter Maydell 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 2/4] Add moxie disassembler Anthony Green 2013-03-03 15:52 ` Blue Swirl 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 3/4] Add sample moxie system Anthony Green 2013-03-03 13:07 ` [Qemu-devel] [PATCH v7 4/4] Add top level changes for moxie Anthony Green
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).