diff options
| author | fishsoupisgood <github@madingley.org> | 2019-04-29 01:17:54 +0100 | 
|---|---|---|
| committer | fishsoupisgood <github@madingley.org> | 2019-05-27 03:43:43 +0100 | 
| commit | 3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch) | |
| tree | 65ca85f13617aee1dce474596800950f266a456c /target-moxie | |
| download | qemu-master.tar.gz qemu-master.tar.bz2 qemu-master.zip  | |
Diffstat (limited to 'target-moxie')
| -rw-r--r-- | target-moxie/Makefile.objs | 2 | ||||
| -rw-r--r-- | target-moxie/cpu.c | 183 | ||||
| -rw-r--r-- | target-moxie/cpu.h | 149 | ||||
| -rw-r--r-- | target-moxie/helper.c | 165 | ||||
| -rw-r--r-- | target-moxie/helper.h | 5 | ||||
| -rw-r--r-- | target-moxie/machine.c | 18 | ||||
| -rw-r--r-- | target-moxie/machine.h | 1 | ||||
| -rw-r--r-- | target-moxie/mmu.c | 36 | ||||
| -rw-r--r-- | target-moxie/mmu.h | 19 | ||||
| -rw-r--r-- | target-moxie/translate.c | 927 | 
10 files changed, 1505 insertions, 0 deletions
diff --git a/target-moxie/Makefile.objs b/target-moxie/Makefile.objs new file mode 100644 index 00000000..6381d4d6 --- /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 00000000..3af37799 --- /dev/null +++ b/target-moxie/cpu.c @@ -0,0 +1,183 @@ +/* + * 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_set_pc(CPUState *cs, vaddr value) +{ +    MoxieCPU *cpu = MOXIE_CPU(cs); + +    cpu->env.pc = value; +} + +static bool moxie_cpu_has_work(CPUState *cs) +{ +    return cs->interrupt_request & CPU_INTERRUPT_HARD; +} + +static void moxie_cpu_reset(CPUState *s) +{ +    MoxieCPU *cpu = MOXIE_CPU(s); +    MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(cpu); +    CPUMoxieState *env = &cpu->env; + +    mcc->parent_reset(s); + +    memset(env, 0, sizeof(CPUMoxieState)); +    env->pc = 0x1000; + +    tlb_flush(s, 1); +} + +static void moxie_cpu_realizefn(DeviceState *dev, Error **errp) +{ +    CPUState *cs = CPU(dev); +    MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(dev); + +    qemu_init_vcpu(cs); +    cpu_reset(cs); + +    mcc->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(cs, &error_abort); + +    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; + +    cc->has_work = moxie_cpu_has_work; +    cc->do_interrupt = moxie_cpu_do_interrupt; +    cc->dump_state = moxie_cpu_dump_state; +    cc->set_pc = moxie_cpu_set_pc; +#ifdef CONFIG_USER_ONLY +    cc->handle_mmu_fault = moxie_cpu_handle_mmu_fault; +#else +    cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug; +    cc->vmsd = &vmstate_moxie_cpu; +#endif + +    /* +     * Reason: moxie_cpu_initfn() calls cpu_exec_init(), which saves +     * the object in cpus -> dangling pointer after final +     * object_unref(). +     */ +    dc->cannot_destroy_with_object_finalize_yet = true; +} + +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) +{ +    return MOXIE_CPU(cpu_generic_init(TYPE_MOXIE_CPU, cpu_model)); +} + +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 00000000..29572aab --- /dev/null +++ b/target-moxie/cpu.h @@ -0,0 +1,149 @@ +/* + *  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 ELF_MACHINE     0xFEED /* EM_MOXIE */ + +#define MOXIE_EX_DIV0        0 +#define MOXIE_EX_BAD         1 +#define MOXIE_EX_IRQ         2 +#define MOXIE_EX_SWI         3 +#define MOXIE_EX_MMU_MISS    4 +#define MOXIE_EX_BREAK      16 + +#include "exec/cpu-defs.h" +#include "fpu/softfloat.h" + +#define TARGET_PAGE_BITS 12     /* 4k */ + +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 + +#define NB_MMU_MODES 1 + +typedef struct CPUMoxieState { + +    uint32_t flags;               /* general execution flags */ +    uint32_t gregs[16];           /* general registers */ +    uint32_t sregs[256];          /* special registers */ +    uint32_t pc;                  /* program counter */ +    /* Instead of saving the cc value, we save the cmp arguments +       and compute cc on demand.  */ +    uint32_t cc_a;                /* reg a for condition code calculation */ +    uint32_t cc_b;                /* reg b for condition code calculation */ + +    void *irq[8]; + +    CPU_COMMON + +} CPUMoxieState; + +#include "qom/cpu.h" + +#define TYPE_MOXIE_CPU "moxie-cpu" + +#define MOXIE_CPU_CLASS(klass) \ +    OBJECT_CLASS_CHECK(MoxieCPUClass, (klass), TYPE_MOXIE_CPU) +#define MOXIE_CPU(obj) \ +    OBJECT_CHECK(MoxieCPU, (obj), TYPE_MOXIE_CPU) +#define MOXIE_CPU_GET_CLASS(obj) \ +    OBJECT_GET_CLASS(MoxieCPUClass, (obj), TYPE_MOXIE_CPU) + +/** + * MoxieCPUClass: + * @parent_reset: The parent class' reset handler. + * + * A Moxie CPU model. + */ +typedef struct MoxieCPUClass { +    /*< private >*/ +    CPUClass parent_class; +    /*< public >*/ + +    DeviceRealize parent_realize; +    void (*parent_reset)(CPUState *cpu); +} MoxieCPUClass; + +/** + * MoxieCPU: + * @env: #CPUMoxieState + * + * A Moxie CPU. + */ +typedef struct MoxieCPU { +    /*< private >*/ +    CPUState parent_obj; +    /*< public >*/ + +    CPUMoxieState env; +} MoxieCPU; + +static inline MoxieCPU *moxie_env_get_cpu(CPUMoxieState *env) +{ +    return container_of(env, MoxieCPU, env); +} + +#define ENV_GET_CPU(e) CPU(moxie_env_get_cpu(e)) + +#define ENV_OFFSET offsetof(MoxieCPU, env) + +MoxieCPU *cpu_moxie_init(const char *cpu_model); +int cpu_moxie_exec(CPUState *cpu); +void moxie_cpu_do_interrupt(CPUState *cs); +void moxie_cpu_dump_state(CPUState *cpu, FILE *f, +                          fprintf_function cpu_fprintf, int flags); +hwaddr moxie_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +void moxie_translate_init(void); +int cpu_moxie_signal_handler(int host_signum, void *pinfo, +                             void *puc); + +#define cpu_init(cpu_model) CPU(cpu_moxie_init(cpu_model)) + +#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_get_tb_cpu_state(CPUMoxieState *env, target_ulong *pc, +                                        target_ulong *cs_base, int *flags) +{ +    *pc = env->pc; +    *cs_base = 0; +    *flags = 0; +} + +int moxie_cpu_handle_mmu_fault(CPUState *cpu, vaddr 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 00000000..6c98965b --- /dev/null +++ b/target-moxie/helper.c @@ -0,0 +1,165 @@ +/* + *  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 "exec/cpu_ldst.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.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(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, +              uintptr_t retaddr) +{ +    int ret; + +    ret = moxie_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx); +    if (unlikely(ret)) { +        if (retaddr) { +            cpu_restore_state(cs, retaddr); +        } +    } +    cpu_loop_exit(cs); +} + +void helper_raise_exception(CPUMoxieState *env, int ex) +{ +    CPUState *cs = CPU(moxie_env_get_cpu(env)); + +    cs->exception_index = ex; +    /* Stash the exception type.  */ +    env->sregs[2] = ex; +    /* Stash the address where the exception occurred.  */ +    cpu_restore_state(cs, GETPC()); +    env->sregs[5] = env->pc; +    /* Jump the the exception handline routine.  */ +    env->pc = env->sregs[1]; +    cpu_loop_exit(cs); +} + +uint32_t helper_div(CPUMoxieState *env, uint32_t a, uint32_t b) +{ +    if (unlikely(b == 0)) { +        helper_raise_exception(env, MOXIE_EX_DIV0); +        return 0; +    } +    if (unlikely(a == INT_MIN && b == -1)) { +        return INT_MIN; +    } + +    return (int32_t)a / (int32_t)b; +} + +uint32_t helper_udiv(CPUMoxieState *env, uint32_t a, uint32_t b) +{ +    if (unlikely(b == 0)) { +        helper_raise_exception(env, MOXIE_EX_DIV0); +        return 0; +    } +    return a / b; +} + +void helper_debug(CPUMoxieState *env) +{ +    CPUState *cs = CPU(moxie_env_get_cpu(env)); + +    cs->exception_index = EXCP_DEBUG; +    cpu_loop_exit(cs); +} + +#if defined(CONFIG_USER_ONLY) + +void moxie_cpu_do_interrupt(CPUState *cs) +{ +    CPUState *cs = CPU(moxie_env_get_cpu(env)); + +    cs->exception_index = -1; +} + +int moxie_cpu_handle_mmu_fault(CPUState *cs, vaddr address, +                               int rw, int mmu_idx) +{ +    MoxieCPU *cpu = MOXIE_CPU(cs); + +    cs->exception_index = 0xaa; +    cpu->env.debug1 = address; +    cpu_dump_state(cs, stderr, fprintf, 0); +    return 1; +} + +#else /* !CONFIG_USER_ONLY */ + +int moxie_cpu_handle_mmu_fault(CPUState *cs, vaddr address, +                               int rw, int mmu_idx) +{ +    MoxieCPU *cpu = MOXIE_CPU(cs); +    CPUMoxieState *env = &cpu->env; +    MoxieMMUResult res; +    int prot, miss; +    target_ulong phy; +    int r = 1; + +    address &= TARGET_PAGE_MASK; +    prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; +    miss = moxie_mmu_translate(&res, env, address, rw, mmu_idx); +    if (miss) { +        /* handle the miss.  */ +        phy = 0; +        cs->exception_index = MOXIE_EX_MMU_MISS; +    } else { +        phy = res.phy; +        r = 0; +    } +    tlb_set_page(cs, address, phy, prot, mmu_idx, TARGET_PAGE_SIZE); +    return r; +} + + +void moxie_cpu_do_interrupt(CPUState *cs) +{ +    switch (cs->exception_index) { +    case MOXIE_EX_BREAK: +        break; +    default: +        break; +    } +} + +hwaddr moxie_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ +    MoxieCPU *cpu = MOXIE_CPU(cs); +    uint32_t phy = addr; +    MoxieMMUResult res; +    int miss; + +    miss = moxie_mmu_translate(&res, &cpu->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 00000000..d94ef7a1 --- /dev/null +++ b/target-moxie/helper.h @@ -0,0 +1,5 @@ +DEF_HELPER_2(raise_exception, void, env, int) +DEF_HELPER_1(debug, void, env) + +DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i32, env, i32, i32) diff --git a/target-moxie/machine.c b/target-moxie/machine.c new file mode 100644 index 00000000..b9316f0e --- /dev/null +++ b/target-moxie/machine.c @@ -0,0 +1,18 @@ +#include "hw/hw.h" +#include "hw/boards.h" +#include "machine.h" + +const VMStateDescription vmstate_moxie_cpu = { +    .name = "cpu", +    .version_id = 1, +    .minimum_version_id = 1, +    .fields = (VMStateField[]) { +        VMSTATE_UINT32(flags, CPUMoxieState), +        VMSTATE_UINT32_ARRAY(gregs, CPUMoxieState, 16), +        VMSTATE_UINT32_ARRAY(sregs, CPUMoxieState, 256), +        VMSTATE_UINT32(pc, CPUMoxieState), +        VMSTATE_UINT32(cc_a, CPUMoxieState), +        VMSTATE_UINT32(cc_b, CPUMoxieState), +        VMSTATE_END_OF_LIST() +    } +}; diff --git a/target-moxie/machine.h b/target-moxie/machine.h new file mode 100644 index 00000000..a1b72907 --- /dev/null +++ b/target-moxie/machine.h @@ -0,0 +1 @@ +extern const VMStateDescription vmstate_moxie_cpu; diff --git a/target-moxie/mmu.c b/target-moxie/mmu.c new file mode 100644 index 00000000..5217eeda --- /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 00000000..abc79297 --- /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 { +    uint32_t phy; +    uint32_t pfn; +    unsigned g:1; +    unsigned v:1; +    unsigned k:1; +    unsigned w:1; +    unsigned 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 00000000..e3e91390 --- /dev/null +++ b/target-moxie/translate.c @@ -0,0 +1,927 @@ +/* + *  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 "exec/cpu_ldst.h" + +#include "exec/helper-proto.h" +#include "exec/helper-gen.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_a, cc_b; + +#include "exec/gen-icount.h" + +#define REG(x) (cpu_gregs[x]) + +/* Extract the signed 10-bit offset from a 16-bit branch +   instruction.  */ +static int extract_branch_offset(int opcode) +{ +  return (((signed short)((opcode & ((1 << 10) - 1)) << 6)) >> 6) << 1; +} + +void moxie_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, +                          int flags) +{ +    MoxieCPU *cpu = MOXIE_CPU(cs); +    CPUMoxieState *env = &cpu->env; +    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]); +    } +    for (i = 4; i < 16; i += 4) { +        cpu_fprintf(f, "sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x\n", +                    i-2, env->sregs[i], i-1, env->sregs[i + 1], +                    i, env->sregs[i + 2], i+1, env->sregs[i + 3]); +    } +} + +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 < 16; i++) +        cpu_gregs[i] = tcg_global_mem_new_i32(TCG_AREG0, +                                              offsetof(CPUMoxieState, gregs[i]), +                                              gregnames[i]); + +    cc_a = tcg_global_mem_new_i32(TCG_AREG0, +                                  offsetof(CPUMoxieState, cc_a), "cc_a"); +    cc_b = tcg_global_mem_new_i32(TCG_AREG0, +                                  offsetof(CPUMoxieState, cc_b), "cc_b"); + +    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((uintptr_t)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); + +#define BRANCH(cond)                                                         \ +    do {                                                                     \ +        TCGLabel *l1 = gen_new_label();                                      \ +        tcg_gen_brcond_i32(cond, cc_a, cc_b, l1);                            \ +        gen_goto_tb(env, ctx, 1, ctx->pc+2);                                 \ +        gen_set_label(l1);                                                   \ +        gen_goto_tb(env, ctx, 0, extract_branch_offset(opcode) + ctx->pc+2); \ +        ctx->bstate = BS_BRANCH;                                             \ +    } while (0) + +            switch (inst) { +            case 0x00: /* beq */ +                BRANCH(TCG_COND_EQ); +                break; +            case 0x01: /* bne */ +                BRANCH(TCG_COND_NE); +                break; +            case 0x02: /* blt */ +                BRANCH(TCG_COND_LT); +                break; +            case 0x03: /* bgt */ +                BRANCH(TCG_COND_GT); +                break; +            case 0x04: /* bltu */ +                BRANCH(TCG_COND_LTU); +                break; +            case 0x05: /* bgtu */ +                BRANCH(TCG_COND_GTU); +                break; +            case 0x06: /* bge */ +                BRANCH(TCG_COND_GE); +                break; +            case 0x07: /* ble */ +                BRANCH(TCG_COND_LE); +                break; +            case 0x08: /* bgeu */ +                BRANCH(TCG_COND_GEU); +                break; +            case 0x09: /* bleu */ +                BRANCH(TCG_COND_LEU); +                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, 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, 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; + +                tcg_gen_mov_i32(cc_a, REG(a)); +                tcg_gen_mov_i32(cc_b, REG(b)); +            } +            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; + +                TCGv sv = tcg_temp_new_i32(); +                tcg_gen_andi_i32(sv, REG(b), 0x1f); +                tcg_gen_shr_i32(REG(a), REG(a), sv); +                tcg_temp_free_i32(sv); +            } +            break; +        case 0x28: /* ashl */ +            { +                int a = (opcode >> 4) & 0xf; +                int b = opcode & 0xf; + +                TCGv sv = tcg_temp_new_i32(); +                tcg_gen_andi_i32(sv, REG(b), 0x1f); +                tcg_gen_shl_i32(REG(a), REG(a), sv); +                tcg_temp_free_i32(sv); +            } +            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; + +                TCGv sv = tcg_temp_new_i32(); +                tcg_gen_andi_i32(sv, REG(b), 0x1f); +                tcg_gen_sar_i32(REG(a), REG(a), sv); +                tcg_temp_free_i32(sv); +            } +            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, 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, 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, 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 */ +            { +                TCGv temp = tcg_temp_new_i32(); +                tcg_gen_movi_i32(cpu_pc, ctx->pc); +                tcg_gen_movi_i32(temp, MOXIE_EX_BREAK); +                gen_helper_raise_exception(cpu_env, temp); +                tcg_temp_free_i32(temp); +            } +            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, temp); +                tcg_temp_free_i32(temp); +             } +            break; +        } +    } + +    return length; +} + +/* generate intermediate code for basic block 'tb'.  */ +static inline void +gen_intermediate_code_internal(MoxieCPU *cpu, TranslationBlock *tb, +                               bool search_pc) +{ +    CPUState *cs = CPU(cpu); +    DisasContext ctx; +    target_ulong pc_start; +    CPUBreakpoint *bp; +    int j, lj = -1; +    CPUMoxieState *env = &cpu->env; +    int num_insns; + +    pc_start = tb->pc; +    ctx.pc = pc_start; +    ctx.saved_pc = -1; +    ctx.tb = tb; +    ctx.memidx = 0; +    ctx.singlestep_enabled = 0; +    ctx.bstate = BS_NONE; +    num_insns = 0; + +    gen_tb_start(tb); +    do { +        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { +            QTAILQ_FOREACH(bp, &cs->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_op_buf_count(); +            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; +            tcg_ctx.gen_opc_icount[lj] = num_insns; +        } +        ctx.opcode = cpu_lduw_code(env, ctx.pc); +        ctx.pc += decode_opc(cpu, &ctx); +        num_insns++; + +        if (cs->singlestep_enabled) { +            break; +        } + +        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) { +            break; +        } +    } while (ctx.bstate == BS_NONE && !tcg_op_buf_full()); + +    if (cs->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: +    gen_tb_end(tb, num_insns); + +    if (search_pc) { +        j = tcg_op_buf_count(); +        lj++; +        while (lj <= j) { +            tcg_ctx.gen_opc_instr_start[lj++] = 0; +        } +    } else { +        tb->size = ctx.pc - pc_start; +        tb->icount = num_insns; +    } +} + +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]; +}  | 
