Patchwork [v5,1/4] Add moxie target code

login
register
mail settings
Submitter Anthony Green
Date Feb. 28, 2013, 5:41 p.m.
Message ID <1362073292-19778-2-git-send-email-green@moxielogic.com>
Download mbox | patch
Permalink /patch/224119/
State New
Headers show

Comments

Anthony Green - Feb. 28, 2013, 5:41 p.m.
Signed-off-by: Anthony Green <green@moxielogic.com>
---
 target-moxie/Makefile.objs |    2 +
 target-moxie/cpu.c         |  174 ++++++++
 target-moxie/cpu.h         |  169 ++++++++
 target-moxie/helper.c      |  100 +++++
 target-moxie/helper.h      |    6 +
 target-moxie/machine.c     |   27 ++
 target-moxie/mmu.c         |   37 ++
 target-moxie/mmu.h         |   19 +
 target-moxie/op_helper.c   |   64 +++
 target-moxie/translate.c   | 1019 ++++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 1617 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/mmu.c
 create mode 100644 target-moxie/mmu.h
 create mode 100644 target-moxie/op_helper.c
 create mode 100644 target-moxie/translate.c
Blue Swirl - Feb. 28, 2013, 7:01 p.m.
On Thu, Feb 28, 2013 at 5:41 PM, Anthony Green <green@moxielogic.com> wrote:
>
> Signed-off-by: Anthony Green <green@moxielogic.com>
> ---
>  target-moxie/Makefile.objs |    2 +
>  target-moxie/cpu.c         |  174 ++++++++
>  target-moxie/cpu.h         |  169 ++++++++
>  target-moxie/helper.c      |  100 +++++
>  target-moxie/helper.h      |    6 +
>  target-moxie/machine.c     |   27 ++
>  target-moxie/mmu.c         |   37 ++
>  target-moxie/mmu.h         |   19 +
>  target-moxie/op_helper.c   |   64 +++
>  target-moxie/translate.c   | 1019 ++++++++++++++++++++++++++++++++++++++++++++
>  10 files changed, 1617 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/mmu.c
>  create mode 100644 target-moxie/mmu.h
>  create mode 100644 target-moxie/op_helper.c
>  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..130db4c
> --- /dev/null
> +++ b/target-moxie/Makefile.objs
> @@ -0,0 +1,2 @@
> +obj-y += translate.o op_helper.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..83b3946
> --- /dev/null
> +++ b/target-moxie/cpu.c
> @@ -0,0 +1,174 @@
> +/*
> + * 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 Lesser General Public
> + * License along with this library; if not, see
> + * <http://www.gnu.org/licenses/lgpl-2.1.html>
> + */
> +
> +#include "cpu.h"
> +#include "qemu-common.h"
> +#include "migration/vmstate.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;
> +}
> +
> +extern const VMStateDescription vmstate_moxie_cpu;

Declarations belong to header files.

> +
> +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..ad9c865
> --- /dev/null
> +++ b/target-moxie/cpu.h
> @@ -0,0 +1,169 @@
> +/*
> + *  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 Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Current address of FSF is:

51 Franklin Street, Fifth Floor
Boston, MA 02110-1301
USA

However, please use the recommended web version like other files.

> + */
> +#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;
> +}
> +
> +
> +#endif /* _CPU_MOXIE_H */
> diff --git a/target-moxie/helper.c b/target-moxie/helper.c
> new file mode 100644
> index 0000000..e1942ba
> --- /dev/null
> +++ b/target-moxie/helper.c
> @@ -0,0 +1,100 @@
> +/*
> + *  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 Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include "config.h"
> +#include "cpu.h"
> +#include "mmu.h"
> +#include "exec/exec-all.h"
> +#include "qemu/host-utils.h"
> +
> +#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, int is_softmmu);

Also this declaration should go to cpu.h.

> +int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
> +                               int rw, int mmu_idx, int is_softmmu)
> +{
> +    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;

Odd indentation. Please use scripts/checkpatch.pl.

> +    } 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;

Also here.

> +    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..4289dbf
> --- /dev/null
> +++ b/target-moxie/helper.h
> @@ -0,0 +1,6 @@
> +#include "exec/def-helper.h"
> +
> +DEF_HELPER_1(debug, void, env)
> +
> +#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/mmu.c b/target-moxie/mmu.c
> new file mode 100644
> index 0000000..9f5e0b0
> --- /dev/null
> +++ b/target-moxie/mmu.c
> @@ -0,0 +1,37 @@
> +/*
> + *  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 Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#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(struct moxie_mmu_result_t *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..e67ed23
> --- /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
> +
> +struct moxie_mmu_result_t {

MoxieMMUResult, don't forget the typedef.

> +    uint32_t phy;
> +    uint32_t pfn;
> +    int g:1;
> +    int v:1;
> +    int k:1;
> +    int w:1;
> +    int e:1;
> +    int cause_op;
> +};
> +
> +int moxie_mmu_translate(struct moxie_mmu_result_t *res,
> +                        CPUMoxieState *env, uint32_t vaddr,
> +                        int rw, int mmu_idx);
> diff --git a/target-moxie/op_helper.c b/target-moxie/op_helper.c
> new file mode 100644
> index 0000000..0c04e09
> --- /dev/null
> +++ b/target-moxie/op_helper.c
> @@ -0,0 +1,64 @@
> +/*
> + *  Moxie helper routines
> + *
> + *  Copyright (c) 2008, 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 Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
> + * USA
> + */
> +
> +#include <assert.h>
> +#include "cpu.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"
> +
> +int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
> +                               int rw, int mmu_idx);

Duplicate declaration once it's in cpu.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_debug(CPUMoxieState *env)
> +{
> +    env->exception_index = EXCP_DEBUG;
> +    cpu_loop_exit(env);
> +}
> diff --git a/target-moxie/translate.c b/target-moxie/translate.c
> new file mode 100644
> index 0000000..0df7028
> --- /dev/null
> +++ b/target-moxie/translate.c
> @@ -0,0 +1,1019 @@
> +/*
> + *  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 Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA
> + * 02110-1301 USA
> + */

Pointers to instruction set documentation would be nice here.

> +
> +#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"
> +
> +#ifdef USE_DIRECT_JUMP
> +#define TBPARAM(x)

This is obsolete.

> +#else
> +#define TBPARAM(x) (long)(x)
> +#endif
> +
> +/* 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;
> +    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");

This is run even if init has been done, move the check earlier.

> +    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_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);

Expressions should always have spaces around operators ('+').

> +                    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:
> +                abort();

This means that user can abort QEMU (crashing the VM) by issuing an
illegal instruction, which is not OK. It should be handled like real
HW, maybe by generating an illegal instruction exception.

> +            }
> +        } 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:
> +                abort();
> +            }
> +        }
> +    } 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 */
> +            {
> +                /* 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+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);                  \

This would be much simpler with setcond or movcond.

Many targets implement lazy condition code evaluation to improve
performance. In this case values of registers a and b would be saved
and only when the specific flag is needed, it is calculated.

> +                    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));

This assumes any shift values make sense and produce the same values
on every host CPU. I'd at least 'and' the shift register value with
0x1f.

> +            }
> +            break;
> +        case 0x28: /* ashl */
> +            {
> +                int a = (opcode >> 4) & 0xf;
> +                int b = opcode & 0xf;
> +
> +                tcg_gen_shl_i32(REG(a), REG(a), REG(b));

Ditto.

> +            }
> +            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 code = tcg_temp_new_i32();
> +
> +                /* Load the stack pointer into T0.  */

T0?

> +                TCGv t1 = tcg_temp_new_i32();
> +                TCGv t2 = tcg_temp_new_i32();
> +
> +                tcg_gen_movi_i32(t1, MOXIE_EX_SWI);
> +                tcg_gen_st_i32(t1, cpu_env, offsetof(CPUMoxieState, sregs[2]));
> +
> +                tcg_gen_movi_i32(code, val);
> +                tcg_gen_st_i32(code, cpu_env,
> +                               offsetof(CPUMoxieState, sregs[3]));
> +
> +                tcg_gen_movi_i32(t1, ctx->pc+6);
> +
> +                /* Make space for the static chain and return address.  */
> +                tcg_gen_subi_i32(t2, REG(1), 4);
> +                tcg_gen_qemu_st32(code, t2, ctx->memidx);
> +
> +                tcg_gen_subi_i32(REG(1), t2, 4);
> +                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_ld_i32(cpu_pc, cpu_env,
> +                               offsetof(CPUMoxieState, sregs[1]));
> +                tcg_temp_free_i32(t1);
> +                tcg_temp_free_i32(t2);
> +                tcg_temp_free_i32(code);
> +                tcg_gen_exit_tb(0);
> +                ctx->bstate = BS_BRANCH;
> +
> +                length = 6;
> +            }
> +            break;
> +        case 0x31: /* div.l */
> +            {
> +                int a = (opcode >> 4) & 0xf;
> +                int b = opcode & 0xf;
> +                tcg_gen_div_i32(REG(a), REG(a), REG(b));
> +            }
> +            break;
> +        case 0x32: /* udiv.l */
> +            {
> +                int a = (opcode >> 4) & 0xf;
> +                int b = opcode & 0xf;
> +                tcg_gen_divu_i32(REG(a), 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);

A breakpoint instruction is different from QEMU debug helpers.
Probably the breakpoint should cause an exception.

> +            }
> +            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:
> +            abort();
> +        }
> +    }
> +
> +    return length;
> +}
> +
> +/* generate intermediate code for basic block 'tb'.  */
> +struct DisasContext ctx;

Please don't use global variables, ctx should be just passed around.

> +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;
> +
> +    if (search_pc) {
> +        qemu_log("search pc %d\n", search_pc);

search_pc is in this case always true, so it's not useful to print it.

> +    }
> +
> +    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:
> +            /* AG FIXME gen_op_interrupt_restart();
> +               gen_op_reset_T0();
> +               gen_op_exit_tb();*/
> +            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.2
>
>

Patch

diff --git a/target-moxie/Makefile.objs b/target-moxie/Makefile.objs
new file mode 100644
index 0000000..130db4c
--- /dev/null
+++ b/target-moxie/Makefile.objs
@@ -0,0 +1,2 @@ 
+obj-y += translate.o op_helper.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..83b3946
--- /dev/null
+++ b/target-moxie/cpu.c
@@ -0,0 +1,174 @@ 
+/*
+ * 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 Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+#include "migration/vmstate.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;
+}
+
+extern const VMStateDescription vmstate_moxie_cpu;
+
+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..ad9c865
--- /dev/null
+++ b/target-moxie/cpu.h
@@ -0,0 +1,169 @@ 
+/*
+ *  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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#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;
+}
+
+
+#endif /* _CPU_MOXIE_H */
diff --git a/target-moxie/helper.c b/target-moxie/helper.c
new file mode 100644
index 0000000..e1942ba
--- /dev/null
+++ b/target-moxie/helper.c
@@ -0,0 +1,100 @@ 
+/*
+ *  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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "mmu.h"
+#include "exec/exec-all.h"
+#include "qemu/host-utils.h"
+
+#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, int is_softmmu);
+int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
+                               int rw, int mmu_idx, int is_softmmu)
+{
+    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..4289dbf
--- /dev/null
+++ b/target-moxie/helper.h
@@ -0,0 +1,6 @@ 
+#include "exec/def-helper.h"
+
+DEF_HELPER_1(debug, void, env)
+
+#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/mmu.c b/target-moxie/mmu.c
new file mode 100644
index 0000000..9f5e0b0
--- /dev/null
+++ b/target-moxie/mmu.c
@@ -0,0 +1,37 @@ 
+/*
+ *  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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#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(struct moxie_mmu_result_t *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..e67ed23
--- /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
+
+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;
+};
+
+int moxie_mmu_translate(struct moxie_mmu_result_t *res,
+                        CPUMoxieState *env, uint32_t vaddr,
+                        int rw, int mmu_idx);
diff --git a/target-moxie/op_helper.c b/target-moxie/op_helper.c
new file mode 100644
index 0000000..0c04e09
--- /dev/null
+++ b/target-moxie/op_helper.c
@@ -0,0 +1,64 @@ 
+/*
+ *  Moxie helper routines
+ *
+ *  Copyright (c) 2008, 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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <assert.h>
+#include "cpu.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"
+
+int cpu_moxie_handle_mmu_fault(CPUMoxieState *env, target_ulong address,
+                               int rw, int mmu_idx);
+
+/* 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_debug(CPUMoxieState *env)
+{
+    env->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(env);
+}
diff --git a/target-moxie/translate.c b/target-moxie/translate.c
new file mode 100644
index 0000000..0df7028
--- /dev/null
+++ b/target-moxie/translate.c
@@ -0,0 +1,1019 @@ 
+/*
+ *  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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA
+ * 02110-1301 USA
+ */
+
+#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"
+
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
+
+/* 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;
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    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_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:
+                abort();
+            }
+        } 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:
+                abort();
+            }
+        }
+    } 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 */
+            {
+                /* 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+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 code = tcg_temp_new_i32();
+
+                /* Load the stack pointer into T0.  */
+                TCGv t1 = tcg_temp_new_i32();
+                TCGv t2 = tcg_temp_new_i32();
+
+                tcg_gen_movi_i32(t1, MOXIE_EX_SWI);
+                tcg_gen_st_i32(t1, cpu_env, offsetof(CPUMoxieState, sregs[2]));
+
+                tcg_gen_movi_i32(code, val);
+                tcg_gen_st_i32(code, cpu_env,
+                               offsetof(CPUMoxieState, sregs[3]));
+
+                tcg_gen_movi_i32(t1, ctx->pc+6);
+
+                /* Make space for the static chain and return address.  */
+                tcg_gen_subi_i32(t2, REG(1), 4);
+                tcg_gen_qemu_st32(code, t2, ctx->memidx);
+
+                tcg_gen_subi_i32(REG(1), t2, 4);
+                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_ld_i32(cpu_pc, cpu_env,
+                               offsetof(CPUMoxieState, sregs[1]));
+                tcg_temp_free_i32(t1);
+                tcg_temp_free_i32(t2);
+                tcg_temp_free_i32(code);
+                tcg_gen_exit_tb(0);
+                ctx->bstate = BS_BRANCH;
+
+                length = 6;
+            }
+            break;
+        case 0x31: /* div.l */
+            {
+                int a = (opcode >> 4) & 0xf;
+                int b = opcode & 0xf;
+                tcg_gen_div_i32(REG(a), REG(a), REG(b));
+            }
+            break;
+        case 0x32: /* udiv.l */
+            {
+                int a = (opcode >> 4) & 0xf;
+                int b = opcode & 0xf;
+                tcg_gen_divu_i32(REG(a), 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:
+            abort();
+        }
+    }
+
+    return length;
+}
+
+/* generate intermediate code for basic block 'tb'.  */
+struct DisasContext ctx;
+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;
+
+    if (search_pc) {
+        qemu_log("search pc %d\n", search_pc);
+    }
+
+    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:
+            /* AG FIXME gen_op_interrupt_restart();
+               gen_op_reset_T0();
+               gen_op_exit_tb();*/
+            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];
+}