diff mbox

[v12,1/9] target-avr: AVR cores support is added.

Message ID 1469318549-41635-2-git-send-email-mrolnik@gmail.com
State New
Headers show

Commit Message

Michael Rolnik July 24, 2016, 12:02 a.m. UTC
1. basic CPU structure
    2. registers
    3. no instructions
    4. saving sreg, rampD, rampX, rampY, rampD, eind in HW representation

Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
 arch_init.c                     |   2 +
 configure                       |   5 +
 default-configs/avr-softmmu.mak |  21 +++
 include/disas/bfd.h             |   6 +
 include/sysemu/arch_init.h      |   1 +
 target-avr/Makefile.objs        |  23 +++
 target-avr/cpu-qom.h            |  85 +++++++++++
 target-avr/cpu.c                | 307 ++++++++++++++++++++++++++++++++++++++++
 target-avr/cpu.h                | 179 +++++++++++++++++++++++
 target-avr/gdbstub.c            |  85 +++++++++++
 target-avr/helper.c             |  87 ++++++++++++
 target-avr/helper.h             |  22 +++
 target-avr/machine.c            | 117 +++++++++++++++
 target-avr/machine.h            |  22 +++
 target-avr/translate.c          | 283 ++++++++++++++++++++++++++++++++++++
 target-avr/translate.h          | 116 +++++++++++++++
 16 files changed, 1361 insertions(+)
 create mode 100644 default-configs/avr-softmmu.mak
 create mode 100644 target-avr/Makefile.objs
 create mode 100644 target-avr/cpu-qom.h
 create mode 100644 target-avr/cpu.c
 create mode 100644 target-avr/cpu.h
 create mode 100644 target-avr/gdbstub.c
 create mode 100644 target-avr/helper.c
 create mode 100644 target-avr/helper.h
 create mode 100644 target-avr/machine.c
 create mode 100644 target-avr/machine.h
 create mode 100644 target-avr/translate.c
 create mode 100644 target-avr/translate.h

Comments

Peter Maydell July 25, 2016, 6:37 p.m. UTC | #1
On 24 July 2016 at 01:02, Michael Rolnik <mrolnik@gmail.com> wrote:
>     1. basic CPU structure
>     2. registers
>     3. no instructions
>     4. saving sreg, rampD, rampX, rampY, rampD, eind in HW representation
>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> ---
>  arch_init.c                     |   2 +
>  configure                       |   5 +
>  default-configs/avr-softmmu.mak |  21 +++
>  include/disas/bfd.h             |   6 +
>  include/sysemu/arch_init.h      |   1 +
>  target-avr/Makefile.objs        |  23 +++
>  target-avr/cpu-qom.h            |  85 +++++++++++
>  target-avr/cpu.c                | 307 ++++++++++++++++++++++++++++++++++++++++
>  target-avr/cpu.h                | 179 +++++++++++++++++++++++
>  target-avr/gdbstub.c            |  85 +++++++++++
>  target-avr/helper.c             |  87 ++++++++++++
>  target-avr/helper.h             |  22 +++
>  target-avr/machine.c            | 117 +++++++++++++++
>  target-avr/machine.h            |  22 +++
>  target-avr/translate.c          | 283 ++++++++++++++++++++++++++++++++++++
>  target-avr/translate.h          | 116 +++++++++++++++
>  16 files changed, 1361 insertions(+)
>  create mode 100644 default-configs/avr-softmmu.mak
>  create mode 100644 target-avr/Makefile.objs
>  create mode 100644 target-avr/cpu-qom.h
>  create mode 100644 target-avr/cpu.c
>  create mode 100644 target-avr/cpu.h
>  create mode 100644 target-avr/gdbstub.c
>  create mode 100644 target-avr/helper.c
>  create mode 100644 target-avr/helper.h
>  create mode 100644 target-avr/machine.c
>  create mode 100644 target-avr/machine.h
>  create mode 100644 target-avr/translate.c
>  create mode 100644 target-avr/translate.h
>
> diff --git a/arch_init.c b/arch_init.c
> index fa05973..be6e6de 100644
> --- a/arch_init.c
> +++ b/arch_init.c
> @@ -80,6 +80,8 @@ int graphic_depth = 32;
>  #define QEMU_ARCH QEMU_ARCH_UNICORE32
>  #elif defined(TARGET_TRICORE)
>  #define QEMU_ARCH QEMU_ARCH_TRICORE
> +#elif defined(TARGET_AVR)
> +#define QEMU_ARCH QEMU_ARCH_AVR
>  #endif
>
>  const uint32_t arch_type = QEMU_ARCH;
> diff --git a/configure b/configure
> index 6ffa4a8..84a4470 100755
> --- a/configure
> +++ b/configure
> @@ -5638,6 +5638,8 @@ case "$target_name" in
>    x86_64)
>      TARGET_BASE_ARCH=i386
>    ;;
> +  avr)
> +  ;;

This case statement is in more or less alphabetical order (the
exceptions are that we keep related cases like i386 and x86_64
together, also 'arm' and 'aarch64') -- could you put the new
'avr' case in the right place just before 'cris', please?

>    alpha)
>    ;;
>    arm|armeb)
> @@ -5834,6 +5836,9 @@ disas_config() {
>
>  for i in $ARCH $TARGET_BASE_ARCH ; do
>    case "$i" in
> +  avr)
> +    disas_config "AVR"
> +  ;;

Similarly for this case.

>    alpha)
>      disas_config "ALPHA"
>    ;;
> diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak
> new file mode 100644
> index 0000000..003465d
> --- /dev/null
> +++ b/default-configs/avr-softmmu.mak
> @@ -0,0 +1,21 @@
> +#
> +#  QEMU AVR CPU
> +#
> +#  Copyright (c) 2016 Michael Rolnik
> +#
> +#  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>
> +#
> +
> +# Default configuration for avr-softmmu
> diff --git a/include/disas/bfd.h b/include/disas/bfd.h
> index 8a3488c..8ccd108 100644
> --- a/include/disas/bfd.h
> +++ b/include/disas/bfd.h
> @@ -213,6 +213,12 @@ enum bfd_architecture
>  #define bfd_mach_m32r          0  /* backwards compatibility */
>    bfd_arch_mn10200,    /* Matsushita MN10200 */
>    bfd_arch_mn10300,    /* Matsushita MN10300 */
> +  bfd_arch_avr,       /* Atmel AVR microcontrollers.  */
> +#define bfd_mach_avr1          1
> +#define bfd_mach_avr2          2
> +#define bfd_mach_avr3          3
> +#define bfd_mach_avr4          4
> +#define bfd_mach_avr5          5
>    bfd_arch_cris,       /* Axis CRIS */
>  #define bfd_mach_cris_v0_v10   255
>  #define bfd_mach_cris_v32      32
> diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
> index d690dfa..8c75777 100644
> --- a/include/sysemu/arch_init.h
> +++ b/include/sysemu/arch_init.h
> @@ -23,6 +23,7 @@ enum {
>      QEMU_ARCH_UNICORE32 = (1 << 14),
>      QEMU_ARCH_MOXIE = (1 << 15),
>      QEMU_ARCH_TRICORE = (1 << 16),
> +    QEMU_ARCH_AVR = (1 << 17),
>  };
>
>  extern const uint32_t arch_type;
> diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs
> new file mode 100644
> index 0000000..2a10104
> --- /dev/null
> +++ b/target-avr/Makefile.objs
> @@ -0,0 +1,23 @@
> +#
> +#  QEMU AVR CPU
> +#
> +#  Copyright (c) 2016 Michael Rolnik
> +#
> +#  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>
> +#
> +
> +obj-y   += translate.o cpu.o helper.o
> +obj-y   += gdbstub.o
> +obj-$(CONFIG_SOFTMMU) += machine.o
> diff --git a/target-avr/cpu-qom.h b/target-avr/cpu-qom.h
> new file mode 100644
> index 0000000..ba60988
> --- /dev/null
> +++ b/target-avr/cpu-qom.h
> @@ -0,0 +1,85 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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>
> + */
> +
> +#ifndef QEMU_AVR_CPU_QOM_H
> +#define QEMU_AVR_CPU_QOM_H
> +
> +#include "qom/cpu.h"
> +
> +#define TYPE_AVR_CPU            "avr"
> +
> +#define AVR_CPU_CLASS(klass)    \
> +                    OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU)
> +#define AVR_CPU(obj)            \
> +                    OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU)
> +#define AVR_CPU_GET_CLASS(obj)  \
> +                    OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_AVR_CPU)
> +
> +/**
> +*  AVRCPUClass:
> +*  @parent_realize: The parent class' realize handler.
> +*  @parent_reset: The parent class' reset handler.
> +*  @vr: Version Register value.
> +*
> +*  A AVR CPU model.
> +*/

Something has gone wrong with the spacing here -- you have
lost the space on the left side of the '*' that makes them
line up (this is correct in the block comment at the top of
this file).

> +typedef struct AVRCPUClass {
> +    CPUClass        parent_class;
> +
> +    DeviceRealize   parent_realize;
> +    void (*parent_reset)(CPUState *cpu);
> +} AVRCPUClass;
> +
> +/**
> +*  AVRCPU:
> +*  @env: #CPUAVRState
> +*
> +*  A AVR CPU.
> +*/
> +typedef struct AVRCPU {
> +    /*< private >*/
> +    CPUState        parent_obj;
> +    /*< public >*/
> +
> +    CPUAVRState     env;
> +} AVRCPU;
> +
> +static inline AVRCPU   *avr_env_get_cpu(CPUAVRState *env)

You only need one space before the '*'.

> +{
> +    return container_of(env, AVRCPU, env);
> +}
> +
> +#define ENV_GET_CPU(e)          CPU(avr_env_get_cpu(e))
> +#define ENV_OFFSET              offsetof(AVRCPU, env)

Better not to have spaces like this or in struct definitions
that try to make things line up -- it tends to result in
more churn later when new fields get added, or else things
stop lining up.

> +#ifndef CONFIG_USER_ONLY
> +extern const struct VMStateDescription vms_avr_cpu;
> +#endif
> +
> +void avr_cpu_do_interrupt(CPUState *cpu);
> +bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req);
> +void avr_cpu_dump_state(CPUState *cs, FILE *f,
> +                            fprintf_function cpu_fprintf, int flags);
> +hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
> +int avr_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
> +int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> +
> +#endif
> +
> diff --git a/target-avr/cpu.c b/target-avr/cpu.c
> new file mode 100644
> index 0000000..7e8d34b
> --- /dev/null
> +++ b/target-avr/cpu.c
> @@ -0,0 +1,307 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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 "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "cpu.h"
> +#include "qemu-common.h"
> +#include "migration/vmstate.h"
> +#include "machine.h"
> +
> +static void avr_cpu_set_pc(CPUState *cs, vaddr value)
> +{
> +    AVRCPU   *cpu = AVR_CPU(cs);
> +
> +    cpu->env.pc_w = value / 2;    /*  internally PC points to words   */
> +}
> +
> +static bool avr_cpu_has_work(CPUState *cs)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +
> +    return      (cs->interrupt_request
> +                &   (CPU_INTERRUPT_HARD
> +                    | CPU_INTERRUPT_RESET))
> +            &&  cpu_interrupts_enabled(env);

Definitely you need to fix this spacing.

> +}
> +
> +static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
> +{
> +    AVRCPU      *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +
> +    env->pc_w = tb->pc / 2;   /*  internally PC points to words   */
> +}
> +
> +static void avr_cpu_reset(CPUState *s)
> +{
> +    AVRCPU *cpu = AVR_CPU(s);
> +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
> +    CPUAVRState *env = &cpu->env;
> +
> +    mcc->parent_reset(s);
> +
> +    env->pc_w = 0;
> +    env->sregI = 1;
> +    env->sregC = 0;
> +    env->sregZ = 0;
> +    env->sregN = 0;
> +    env->sregV = 0;
> +    env->sregS = 0;
> +    env->sregH = 0;
> +    env->sregT = 0;
> +
> +    env->rampD = 0;
> +    env->rampX = 0;
> +    env->rampY = 0;
> +    env->rampZ = 0;
> +    env->eind = 0;
> +    env->sp = 0;
> +
> +    memset(env->io, 0, sizeof(env->io));
> +    memset(env->r, 0, sizeof(env->r));
> +
> +    tlb_flush(s, 1);
> +}
> +
> +static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
> +{
> +    info->mach = bfd_arch_avr;
> +    info->print_insn = NULL;
> +}
> +
> +static void avr_cpu_realizefn(DeviceState *dev, Error **errp)
> +{
> +    CPUState *cs = CPU(dev);
> +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev);
> +
> +    qemu_init_vcpu(cs);
> +    cpu_reset(cs);
> +
> +    mcc->parent_realize(dev, errp);
> +}
> +
> +static void avr_cpu_set_int(void *opaque, int irq, int level)
> +{
> +    AVRCPU *cpu = opaque;
> +    CPUAVRState *env = &cpu->env;
> +    CPUState *cs = CPU(cpu);
> +
> +    uint64_t mask = (1ull << irq);
> +    if (level) {
> +        env->intsrc |=  mask;
> +        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
> +    } else {
> +        env->intsrc &= ~mask;
> +        if (env->intsrc == 0) {
> +            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
> +        }
> +    }
> +}
> +
> +static void avr_cpu_initfn(Object *obj)
> +{
> +    CPUState *cs = CPU(obj);
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    static int inited;
> +
> +    cs->env_ptr = &cpu->env;
> +    cpu_exec_init(cs, &error_abort);
> +
> +#ifndef CONFIG_USER_ONLY
> +    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 37);
> +#endif
> +
> +    if (tcg_enabled() && !inited) {
> +        inited = 1;
> +        avr_translate_init();
> +    }
> +}
> +
> +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
> +{
> +    ObjectClass *oc;
> +    char *typename;
> +    char **cpuname;
> +
> +    if (!cpu_model) {
> +        return NULL;
> +    }
> +
> +    cpuname = g_strsplit(cpu_model, ",", 1);
> +    typename = g_strdup_printf("%s-" TYPE_AVR_CPU, cpuname[0]);
> +    oc = object_class_by_name(typename);
> +
> +    g_strfreev(cpuname);
> +    g_free(typename);
> +
> +    if (!oc
> +        ||  !object_class_dynamic_cast(oc, TYPE_AVR_CPU)
> +        ||  object_class_is_abstract(oc)) {
> +        return NULL;
> +    }
> +
> +    return oc;
> +}
> +
> +static void avr_cpu_class_init(ObjectClass *oc, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +    CPUClass *cc = CPU_CLASS(oc);
> +    AVRCPUClass *mcc = AVR_CPU_CLASS(oc);
> +
> +    mcc->parent_realize = dc->realize;
> +    dc->realize = avr_cpu_realizefn;
> +
> +    mcc->parent_reset = cc->reset;
> +    cc->reset = avr_cpu_reset;
> +
> +    cc->class_by_name = avr_cpu_class_by_name;
> +
> +    cc->has_work = avr_cpu_has_work;
> +    cc->do_interrupt = avr_cpu_do_interrupt;
> +    cc->cpu_exec_interrupt = avr_cpu_exec_interrupt;
> +    cc->dump_state = avr_cpu_dump_state;
> +    cc->set_pc = avr_cpu_set_pc;
> +#if !defined(CONFIG_USER_ONLY)
> +    cc->memory_rw_debug = avr_cpu_memory_rw_debug;
> +#endif
> +#ifdef CONFIG_USER_ONLY
> +    cc->handle_mmu_fault = avr_cpu_handle_mmu_fault;
> +#else
> +    cc->get_phys_page_debug = avr_cpu_get_phys_page_debug;
> +    cc->vmsd = &vms_avr_cpu;
> +#endif
> +    cc->disas_set_info = avr_cpu_disas_set_info;
> +    cc->synchronize_from_tb = avr_cpu_synchronize_from_tb;
> +    cc->gdb_read_register = avr_cpu_gdb_read_register;
> +    cc->gdb_write_register = avr_cpu_gdb_write_register;
> +    cc->gdb_num_core_regs = 35;
> +
> +    /*
> +     * Reason: avr_cpu_initfn() calls cpu_exec_init(), which saves
> +     * the object in cpus -> dangling pointer after final
> +     * object_unref().
> +     */
> +    dc->cannot_destroy_with_object_finalize_yet = true;
> +}
> +
> +static void avr_any_initfn(Object *obj)
> +{
> +    /* Set cpu feature flags */
> +}
> +
> +typedef struct AVRCPUInfo {
> +    const char     *name;
> +    void (*initfn)(Object *obj);
> +} AVRCPUInfo;
> +
> +static const AVRCPUInfo avr_cpus[] = {
> +    {   .name = "any",      .initfn = avr_any_initfn },
> +};
> +
> +static gint avr_cpu_list_compare(gconstpointer a, gconstpointer b)
> +{
> +    ObjectClass *class_a = (ObjectClass *)a;
> +    ObjectClass *class_b = (ObjectClass *)b;
> +    const char *name_a;
> +    const char *name_b;
> +
> +    name_a = object_class_get_name(class_a);
> +    name_b = object_class_get_name(class_b);
> +    if (strcmp(name_a, "any-" TYPE_AVR_CPU) == 0) {
> +        return 1;
> +    } else if (strcmp(name_b, "any-" TYPE_AVR_CPU) == 0) {
> +        return -1;
> +    } else {
> +        return strcmp(name_a, name_b);
> +    }
> +}
> +
> +static void avr_cpu_list_entry(gpointer data, gpointer user_data)
> +{
> +    ObjectClass *oc = data;
> +    CPUListState *s = user_data;
> +    const char *typename;
> +    char *name;
> +
> +    typename = object_class_get_name(oc);
> +    name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_AVR_CPU));
> +    (*s->cpu_fprintf)(s->file, "  %s\n", name);
> +    g_free(name);
> +}
> +
> +void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf)
> +{
> +    CPUListState s = {
> +        .file = f,
> +        .cpu_fprintf = cpu_fprintf,
> +    };
> +    GSList *list;
> +
> +    list = object_class_get_list(TYPE_AVR_CPU, false);
> +    list = g_slist_sort(list, avr_cpu_list_compare);
> +    (*cpu_fprintf)(f, "Available CPUs:\n");
> +    g_slist_foreach(list, avr_cpu_list_entry, &s);
> +    g_slist_free(list);
> +}
> +
> +AVRCPU *cpu_avr_init(const char *cpu_model)
> +{
> +    return AVR_CPU(cpu_generic_init(TYPE_AVR_CPU, cpu_model));
> +}
> +
> +static void cpu_register(const AVRCPUInfo *info)
> +{
> +    TypeInfo type_info = {
> +        .parent = TYPE_AVR_CPU,
> +        .instance_size = sizeof(AVRCPU),
> +        .instance_init = info->initfn,
> +        .class_size = sizeof(AVRCPUClass),
> +    };
> +
> +    type_info.name = g_strdup_printf("%s-" TYPE_AVR_CPU, info->name);
> +    type_register(&type_info);
> +    g_free((void *)type_info.name);
> +}
> +
> +static const TypeInfo avr_cpu_type_info = {
> +    .name = TYPE_AVR_CPU,
> +    .parent = TYPE_CPU,
> +    .instance_size = sizeof(AVRCPU),
> +    .instance_init = avr_cpu_initfn,
> +    .class_size = sizeof(AVRCPUClass),
> +    .class_init = avr_cpu_class_init,
> +    .abstract = true,
> +};
> +
> +static void avr_cpu_register_types(void)
> +{
> +    int i;
> +    type_register_static(&avr_cpu_type_info);
> +
> +    for (i = 0; i < ARRAY_SIZE(avr_cpus); i++) {
> +        cpu_register(&avr_cpus[i]);
> +    }
> +}
> +
> +type_init(avr_cpu_register_types)
> +
> diff --git a/target-avr/cpu.h b/target-avr/cpu.h
> new file mode 100644
> index 0000000..6bc8b86
> --- /dev/null
> +++ b/target-avr/cpu.h
> @@ -0,0 +1,179 @@
> + /*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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>
> + */
> +
> +#if !defined(CPU_AVR_H)
> +#define CPU_AVR_H
> +
> +#include "qemu-common.h"
> +
> +#define TARGET_LONG_BITS            32
> +
> +#define CPUArchState struct CPUAVRState
> +
> +#include "exec/cpu-defs.h"
> +#include "fpu/softfloat.h"
> +
> +/*
> +    TARGET_PAGE_BITS cannot be more than 8 bits because
> +    1.  all IO registers occupy [0x0000 .. 0x00ff] address range, and they
> +        should be implemented as a device and not memory
> +    2.  SRAM starts at the address 0x0100
> +*/

This comment is misformatted (as are others in this file);
please be consistent.

> +#define TARGET_PAGE_BITS            8
> +#define TARGET_PHYS_ADDR_SPACE_BITS 24
> +#define TARGET_VIRT_ADDR_SPACE_BITS 24
> +#define NB_MMU_MODES                2
> +
> +#define MMU_CODE_IDX                0
> +#define MMU_DATA_IDX                1

This would be a good place for a comment explaining why these
need different MMU indexes. How do code and data accesses
behave differently? For most CPUs they both get the same MMU
index (and different MMU indexes separate user access from
kernel access, etc). PPC is the only existing CPU that has to
do something weird here. The natural expectation for a CPU
like AVR which doesn't have an actual MMU would be for
everything to use a single index (0), so it's helpful
to explain to the reader what's going on.

> +
> +#define EXCP_RESET                  1
> +#define EXCP_INT(n)                 (EXCP_RESET + (n) + 1)
> +
> +#define PHYS_ADDR_MASK              0xfff00000
> +
> +#define PHYS_BASE_CODE              0x00000000
> +#define PHYS_BASE_DATA              0x00800000
> +#define PHYS_BASE_REGS              0x10000000
> +
> +#define VIRT_BASE_CODE              0x00000000
> +#define VIRT_BASE_DATA              0x00000000
> +#define VIRT_BASE_REGS              0x00000000
> +
> +/*
> +    there are three groups of registers
> +    1. CPU regs     - accessable by LD/ST and CPU itself
> +    2. CPU IO regs  - accessable by LD/ST and IN/OUT
> +    3. EXT IO regs  - accessable by LD/ST

"accessible"

> +*/
> +#define AVR_CPU_REGS                0x0020
> +#define AVR_CPU_IO_REGS             0x0040
> +#define AVR_EXT_IO_REGS             0x00a0
> +#define AVR_IO_REGS                 (AVR_CPU_IO_REGS + AVR_EXT_IO_REGS)
> +#define AVR_REGS                    (AVR_IO_REGS + AVR_CPU_REGS)
> +
> +#define AVR_CPU_REGS_BASE           0x0000
> +#define AVR_CPU_IO_REGS_BASE        (AVR_CPU_REGS_BASE + AVR_CPU_REGS)
> +#define AVR_EXT_IO_REGS_BASE        (AVR_CPU_IO_REGS_BASE + AVR_CPU_IO_REGS)
> +
> +#define AVR_CPU_REGS_LAST           (AVR_CPU_REGS_BASE + AVR_CPU_REGS - 1)
> +#define AVR_CPU_IO_REGS_LAST        (AVR_CPU_IO_REGS_BASE + AVR_CPU_IO_REGS - 1)
> +#define AVR_EXT_IO_REGS_LAST        (AVR_EXT_IO_REGS_BASE + AVR_EXT_IO_REGS - 1)
> +
> +typedef struct CPUAVRState CPUAVRState;
> +
> +struct CPUAVRState {
> +    uint32_t        pc_w;   /*   0x003fffff up to 22 bits           */
> +
> +    uint32_t        sregC;  /*   0x00000001 1 bits                  */
> +    uint32_t        sregZ;  /*   0x0000ffff 16 bits, negative logic */
> +    uint32_t        sregN;  /*   0x00000001 1 bits                  */
> +    uint32_t        sregV;  /*   0x00000001 1 bits                  */
> +    uint32_t        sregS;  /*   0x00000001 1 bits                  */
> +    uint32_t        sregH;  /*   0x00000001 1 bits                  */
> +    uint32_t        sregT;  /*   0x00000001 1 bits                  */
> +    uint32_t        sregI;  /*   0x00000001 1 bits                  */
> +
> +    uint32_t        rampD;  /*   0x00ff0000 8 bits                  */
> +    uint32_t        rampX;  /*   0x00ff0000 8 bits                  */
> +    uint32_t        rampY;  /*   0x00ff0000 8 bits                  */
> +    uint32_t        rampZ;  /*   0x00ff0000 8 bits                  */
> +    uint32_t        eind;   /*   0x00ff0000 8 bits                  */
> +
> +    uint32_t        io[AVR_CPU_IO_REGS];
> +                            /*   8 bits each                        */
> +    uint32_t        r[AVR_CPU_REGS];
> +                            /*   8 bits each                        */
> +    uint32_t        sp;     /*   16 bits                            */
> +
> +    uint64_t        intsrc; /*  interrupt sources                   */
> +
> +    /* Those resources are used only in QEMU core */
> +    CPU_COMMON
> +};
> +
> +#define cpu_list            avr_cpu_list
> +#define cpu_signal_handler  cpu_avr_signal_handler
> +
> +#include "exec/cpu-all.h"
> +#include "cpu-qom.h"
> +
> +static inline int cpu_mmu_index(CPUAVRState *env, bool ifetch)
> +{
> +    return  ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
> +}
> +
> +void avr_translate_init(void);
> +
> +AVRCPU *cpu_avr_init(const char *cpu_model);
> +
> +#define cpu_init(cpu_model) CPU(cpu_avr_init(cpu_model))
> +
> +void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf);
> +int cpu_avr_exec(CPUState *cpu);
> +int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc);
> +int avr_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
> +                                int mmu_idx);
> +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
> +                                int len, bool is_write);
> +
> +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc,
> +                                target_ulong *cs_base, uint32_t *pflags)
> +{
> +    *pc = env->pc_w * 2;
> +    *cs_base = 0;
> +    *pflags = 0;
> +}
> +
> +static inline int cpu_interrupts_enabled(CPUAVRState *env1)
> +{
> +    return  env1->sregI != 0;

You can call the argument here "env" rather than "env1" (other
targets which use env1 do so for historical reasons only).

You don't need the double space after "return" either.
I'm going to stop commenting on spacing weirdness here, but
please go through and sort it all out.

> +}
> +
> +static inline uint8_t cpu_get_sreg(CPUAVRState *env)
> +{
> +    uint8_t sreg;
> +    sreg = (env->sregC & 0x01) << 0
> +            | (env->sregZ == 0 ? 1 : 0) << 1
> +            | (env->sregN) << 2
> +            | (env->sregV) << 3
> +            | (env->sregS) << 4
> +            | (env->sregH) << 5
> +            | (env->sregT) << 6
> +            | (env->sregI) << 7;
> +    return  sreg;
> +}
> +
> +static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg)
> +{
> +    env->sregC = (sreg >> 0) & 0x01;
> +    env->sregZ = (sreg >> 1) & 0x01 ? 0 : 1;
> +    env->sregN = (sreg >> 2) & 0x01;
> +    env->sregV = (sreg >> 3) & 0x01;
> +    env->sregS = (sreg >> 4) & 0x01;
> +    env->sregH = (sreg >> 5) & 0x01;
> +    env->sregT = (sreg >> 6) & 0x01;
> +    env->sregI = (sreg >> 7) & 0x01;
> +}
> +
> +#include "exec/exec-all.h"
> +
> +#endif /* !defined (CPU_AVR_H) */
> +
> diff --git a/target-avr/gdbstub.c b/target-avr/gdbstub.c
> new file mode 100644
> index 0000000..e05b7e1
> --- /dev/null
> +++ b/target-avr/gdbstub.c
> @@ -0,0 +1,85 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "exec/gdbstub.h"
> +
> +int avr_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +
> +    /*  R */
> +    if (n < 32) {
> +        return gdb_get_reg8(mem_buf, env->r[n]);
> +    }
> +
> +    /*  SREG */
> +    if (n == 32) {
> +        uint8_t sreg = cpu_get_sreg(env);
> +
> +        return gdb_get_reg8(mem_buf, sreg);
> +    }
> +
> +    /*  SP */
> +    if (n == 33) {
> +        return  gdb_get_reg16(mem_buf, env->sp & 0x0000ffff);
> +    }
> +
> +    /*  PC */
> +    if (n == 34) {
> +        return  gdb_get_reg32(mem_buf, env->pc_w * 2);
> +    }
> +
> +    return 0;
> +}
> +
> +int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +    uint16_t tmp = ldl_p(mem_buf);

Something is odd here. In the read_register function above
you write a number of bytes which depends on the register
(1, 2 or 4 depending on register size). Here you are
always reading 4 bytes (which you then throw away two of
by using a uint16_t). How many bytes of data are actually
sent and received by gdb in the remote protocol?

> +
> +    /*  R */
> +    if (n < 32) {
> +        env->r[n] = tmp;
> +    }
> +
> +    /*  SREG */
> +    if (n == 32) {
> +        cpu_set_sreg(env, tmp);
> +    }
> +
> +    /*  SP */
> +    if (n == 33) {
> +        env->sp = tmp;
> +        return  2;
> +    }
> +
> +    /*  PC */
> +    if (n == 34) {
> +        env->pc_w = tmp / 2;
> +        return  4;
> +    }
> +
> +    return 1;

Why 1?

> +}
> +
> diff --git a/target-avr/helper.c b/target-avr/helper.c
> new file mode 100644
> index 0000000..ffc9378
> --- /dev/null
> +++ b/target-avr/helper.c
> @@ -0,0 +1,87 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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 "qemu/osdep.h"
> +
> +#include "cpu.h"
> +#include "hw/irq.h"
> +#include "include/hw/sysbus.h"
> +#include "include/sysemu/sysemu.h"
> +#include "exec/exec-all.h"
> +#include "exec/cpu_ldst.h"
> +#include "qemu/host-utils.h"
> +#include "exec/helper-proto.h"
> +
> +bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
> +{
> +    return  false;
> +}
> +
> +void avr_cpu_do_interrupt(CPUState *cs)
> +{
> +}
> +
> +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf,
> +                                int len, bool is_write)
> +{
> +    return  cpu_memory_rw_debug(cs, addr, buf, len, is_write);
> +}

You don't need to implement this if you don't need to do anything
special in it.

> +
> +hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
> +{
> +    return  addr;   /*  I assume 1:1 address correspondance */
> +}
> +
> +int avr_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx)
> +{
> +    cs->exception_index = EXCP_DEBUG;
> +    cpu_dump_state(cs, stderr, fprintf, 0);

Is this a "can't happen" state ? If so, a comment saying so would be useful.

> +    return 1;
> +}
> +
> +void tlb_fill(CPUState *cs, target_ulong vaddr, MMUAccessType access_type,
> +                                int mmu_idx, uintptr_t retaddr)
> +{
> +    target_ulong page_size = TARGET_PAGE_SIZE;
> +    int prot = 0;
> +    MemTxAttrs attrs = {};
> +    uint32_t paddr;
> +
> +    vaddr &= TARGET_PAGE_MASK;
> +
> +    if (mmu_idx == MMU_CODE_IDX) {
> +        paddr = PHYS_BASE_CODE + vaddr;
> +        prot = PAGE_READ | PAGE_EXEC;
> +    } else {
> +        paddr = PHYS_BASE_DATA + vaddr;
> +        prot = PAGE_READ | PAGE_WRITE;
> +    }
> +
> +    tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size);
> +}
> +
> +void helper_debug(CPUAVRState *env)
> +{
> +    CPUState *cs = CPU(avr_env_get_cpu(env));
> +
> +    cs->exception_index = EXCP_DEBUG;
> +    cpu_loop_exit(cs);
> +}
> +
> diff --git a/target-avr/helper.h b/target-avr/helper.h
> new file mode 100644
> index 0000000..c60ac3e
> --- /dev/null
> +++ b/target-avr/helper.h
> @@ -0,0 +1,22 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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>
> + */
> +
> +DEF_HELPER_1(debug, void, env)
> +
> diff --git a/target-avr/machine.c b/target-avr/machine.c
> new file mode 100644
> index 0000000..5c8049e
> --- /dev/null
> +++ b/target-avr/machine.c
> @@ -0,0 +1,117 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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 "qemu/osdep.h"
> +#include "hw/hw.h"
> +#include "cpu.h"
> +#include "hw/boards.h"
> +#include "machine.h"
> +#include "migration/qemu-file.h"
> +
> +static int get_sreg(QEMUFile *f, void *opaque, size_t size)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg;
> +
> +    qemu_get_8s(f, &sreg);

Better to use
     sreg = qemu_get_ubyte(f);
since we don't specifically want to write the value to
a particular location.

> +    cpu_set_sreg(env, sreg);

> +    return 0;
> +}
> +
> +static void put_sreg(QEMUFile *f, void *opaque, size_t size)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg = cpu_get_sreg(env);
> +
> +    qemu_put_8s(f, &sreg);

Similarly:
    qemu_put_ubyte(f, sreg);

and ditto below.

> +}
> +
> +static const VMStateInfo vms_sreg = {
> +    .name = "sreg",
> +    .get  = get_sreg,
> +    .put  = put_sreg,
> +};
> +
> +static int get_segment(QEMUFile *f, void *opaque, size_t size)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp = *ramp >> 16;
> +
> +    qemu_get_8s(f, &temp);
> +    return 0;
> +}
> +
> +static void put_segment(QEMUFile *f, void *opaque, size_t size)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp = 0;
> +
> +    qemu_put_8s(f, &temp);
> +    *ramp = ((uint32_t)temp) << 16;
> +}
> +
> +static const VMStateInfo vms_rampD = {
> +    .name = "rampD",
> +    .get  = get_segment,
> +    .put  = put_segment,
> +};
> +static const VMStateInfo vms_rampX = {
> +    .name = "rampX",
> +    .get  = get_segment,
> +    .put  = put_segment,
> +};
> +static const VMStateInfo vms_rampY = {
> +    .name = "rampY",
> +    .get  = get_segment,
> +    .put  = put_segment,
> +};
> +static const VMStateInfo vms_rampZ = {
> +    .name = "rampZ",
> +    .get  = get_segment,
> +    .put  = put_segment,
> +};
> +static const VMStateInfo vms_eind = {
> +    .name = "eind",
> +    .get  = get_segment,
> +    .put  = put_segment,
> +};
> +
> +const VMStateDescription vms_avr_cpu = {
> +    .name               = "cpu",
> +    .version_id         = 0,
> +    .minimum_version_id = 0,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(env.pc_w, AVRCPU),
> +        VMSTATE_UINT32(env.sp, AVRCPU),
> +
> +        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, AVR_CPU_REGS),
> +        VMSTATE_UINT32_ARRAY(env.io, AVRCPU, AVR_CPU_IO_REGS),
> +
> +        VMSTATE_SINGLE_TEST(env, AVRCPU, NULL, 0, vms_sreg, CPUAVRState),
> +        VMSTATE_SINGLE_TEST(env.rampD, AVRCPU, NULL, 0, vms_rampD, uint32_t),
> +        VMSTATE_SINGLE_TEST(env.rampX, AVRCPU, NULL, 0, vms_rampX, uint32_t),
> +        VMSTATE_SINGLE_TEST(env.rampY, AVRCPU, NULL, 0, vms_rampY, uint32_t),
> +        VMSTATE_SINGLE_TEST(env.rampZ, AVRCPU, NULL, 0, vms_rampZ, uint32_t),
> +        VMSTATE_SINGLE_TEST(env.eind, AVRCPU, NULL, 0, vms_eind, uint32_t),

If you're going to use a NULL test argument this is equivalent
to VMSTATE_SINGLE().

Mostly we tend to go for migrating the state as we store it
(which in this case would mean just sending the ramp* values
as uint32_t rather than extracting the 8 important bits and
sending just those), but if you want to do it this way around
I don't object.

> +
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> diff --git a/target-avr/machine.h b/target-avr/machine.h
> new file mode 100644
> index 0000000..cc22888
> --- /dev/null
> +++ b/target-avr/machine.h
> @@ -0,0 +1,22 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2016 Michael Rolnik
> + *
> + * 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>
> + */
> +
> +extern const VMStateDescription vmstate_avr_cpu;

You already have an extern declaration of this in qom-cpu.h;
you don't need two.

If you want to keep this one then the header needs the
usual multiple-inclusion guards.

> +
> diff --git a/target-avr/translate.c b/target-avr/translate.c
> new file mode 100644
> index 0000000..ce87c11
> --- /dev/null
> +++ b/target-avr/translate.c
> @@ -0,0 +1,283 @@
> +/*
> + *  QEMU AVR CPU
> + *
> + *  Copyright (c) 2016 Michael Rolnik
> + *
> + *  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 "translate.h"
> +
> +TCGv_env cpu_env;
> +
> +TCGv     cpu_pc;
> +
> +TCGv     cpu_Cf;
> +TCGv     cpu_Zf;
> +TCGv     cpu_Nf;
> +TCGv     cpu_Vf;
> +TCGv     cpu_Sf;
> +TCGv     cpu_Hf;
> +TCGv     cpu_Tf;
> +TCGv     cpu_If;
> +
> +TCGv     cpu_rampD;
> +TCGv     cpu_rampX;
> +TCGv     cpu_rampY;
> +TCGv     cpu_rampZ;
> +
> +TCGv     cpu_io[64];
> +TCGv     cpu_r[32];
> +TCGv     cpu_eind;
> +TCGv     cpu_sp;
> +
> +#include "exec/gen-icount.h"
> +#define REG(x)  (cpu_r[x])
> +
> +void avr_translate_init(void)
> +{
> +    int i;
> +    static int done_init;
> +
> +    if (done_init) {
> +        return;
> +    }
> +#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x)
> +    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
> +    cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w),  "pc");
> +    cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf");
> +    cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf");
> +    cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf");
> +    cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf");
> +    cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf");
> +    cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf");
> +    cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf");
> +    cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If");
> +    cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD");
> +    cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX");
> +    cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY");
> +    cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ");
> +    cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind),  "eind");
> +    cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp),    "sp");
> +
> +    for (i = 0; i < 64; i++) {
> +        char    name[16];
> +
> +        sprintf(name, "io[%d]", i);
> +
> +        cpu_io[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(io[i]), name);
> +    }
> +    for (i = 0; i < 32; i++) {
> +        char    name[16];
> +
> +        sprintf(name, "r[%d]", i);
> +
> +        cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), name);
> +    }
> +
> +    done_init = 1;
> +}
> +
> +static int translate_nop(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
> +{
> +    return BS_NONE;
> +}
> +
> +void avr_decode(uint32_t pc, uint32_t *length, uint32_t opcode,
> +                        translate_function_t *translate)
> +{
> +    *length = 32;
> +    *translate = &translate_nop;
> +}
> +
> +static void decode_opc(AVRCPU *cpu, DisasContext *ctx, InstInfo *inst)
> +{
> +    CPUAVRState        *env = &cpu->env;
> +
> +    inst->opcode = cpu_ldl_code(env, inst->cpc * 2);/*  pc points to words  */
> +    inst->length = 16;
> +    inst->translate = NULL;
> +
> +    /*  the following function looks onto the opcode as a string of bytes   */
> +    avr_decode(inst->cpc, &inst->length, inst->opcode, &inst->translate);
> +
> +    if (inst->length == 16) {
> +        inst->npc = inst->cpc + 1;
> +        /*  get opcode as 16bit value   */
> +        inst->opcode = inst->opcode & 0x0000ffff;
> +    }
> +    if (inst->length == 32) {
> +        inst->npc = inst->cpc + 2;
> +        /*  get opcode as 32bit value   */
> +        inst->opcode = (inst->opcode << 16)
> +                     | (inst->opcode >> 16);
> +    }
> +}
> +
> +/*generate intermediate code for basic block 'tb'.  */
> +void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb)
> +{
> +    AVRCPU         *cpu = avr_env_get_cpu(env);
> +    CPUState       *cs = CPU(cpu);
> +    DisasContext    ctx;
> +    target_ulong    pc_start;
> +    int             num_insns,
> +                    max_insns;
> +    target_ulong    cpc;
> +    target_ulong    npc;
> +
> +    pc_start = tb->pc / 2;
> +    ctx.tb = tb;
> +    ctx.memidx = 0;
> +    ctx.bstate = BS_NONE;
> +    ctx.singlestep = cs->singlestep_enabled;
> +    num_insns = 0;
> +    max_insns = tb->cflags & CF_COUNT_MASK;
> +
> +    if (max_insns == 0) {
> +        max_insns = CF_COUNT_MASK;
> +    }
> +    if (max_insns > TCG_MAX_INSNS) {
> +        max_insns = TCG_MAX_INSNS;
> +    }
> +
> +    gen_tb_start(tb);
> +
> +    /*  decode first instruction    */
> +    ctx.inst[0].cpc = pc_start;
> +    decode_opc(cpu, &ctx, &ctx.inst[0]);
> +    do {
> +        /*  set curr/next PCs   */
> +        cpc = ctx.inst[0].cpc;
> +        npc = ctx.inst[0].npc;
> +
> +        /*  decode next instruction */
> +        ctx.inst[1].cpc = ctx.inst[0].npc;
> +        decode_opc(cpu, &ctx, &ctx.inst[1]);
> +
> +        /*  translate current instruction */
> +        tcg_gen_insn_start(cpc);
> +        num_insns++;
> +
> +        if (unlikely(cpu_breakpoint_test(cs, cpc * 2, BP_ANY))) {
> +            tcg_gen_movi_i32(cpu_pc, cpc);
> +            gen_helper_debug(cpu_env);
> +            ctx.bstate = BS_EXCP;
> +            /*The address covered by the breakpoint must be included in
> +               [tb->pc, tb->pc + tb->size) in order to for it to be
> +               properly cleared -- thus we increment the PC here so that
> +               the logic setting tb->size below does the right thing.  */
> +            goto done_generating;
> +        }
> +
> +        ctx.bstate = ctx.inst[0].translate(env, &ctx, ctx.inst[0].opcode);
> +
> +        if (num_insns >= max_insns) {
> +            break;      /* max translated instructions limit reached */
> +        }
> +        if (ctx.singlestep) {
> +            break;      /* single step */
> +        }
> +        if ((cpc & (TARGET_PAGE_SIZE - 1)) == 0) {
> +            break;      /* page boundary */
> +        }
> +
> +        ctx.inst[0] = ctx.inst[1];  /*  make next inst curr */
> +    } while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
> +
> +    if (tb->cflags & CF_LAST_IO) {
> +        gen_io_end();
> +    }
> +
> +    if (ctx.singlestep) {
> +        if (ctx.bstate == BS_STOP || ctx.bstate == BS_NONE) {
> +            tcg_gen_movi_tl(cpu_pc, npc);
> +        }
> +        gen_helper_debug(cpu_env);
> +        tcg_gen_exit_tb(0);
> +    } else {
> +        switch (ctx.bstate) {
> +        case BS_STOP:
> +        case BS_NONE:
> +            gen_goto_tb(env, &ctx, 0, npc);
> +            break;
> +        case BS_EXCP:
> +            tcg_gen_exit_tb(0);
> +            break;
> +        default:
> +            break;
> +        }
> +    }
> +
> +done_generating:
> +    gen_tb_end(tb, num_insns);
> +
> +    tb->size = (npc - pc_start) * 2;
> +    tb->icount = num_insns;
> +}
> +
> +void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb,
> +                            target_ulong *data)
> +{
> +    env->pc_w = data[0];
> +}
> +
> +void avr_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
> +                            int flags)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +    int i;
> +
> +    cpu_fprintf(f, "\n");
> +    cpu_fprintf(f, "PC:    %06x\n", env->pc_w);
> +    cpu_fprintf(f, "SP:      %04x\n", env->sp);
> +    cpu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
> +    cpu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
> +    cpu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
> +    cpu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
> +    cpu_fprintf(f, "EIND:      %02x\n", env->eind);
> +    cpu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
> +    cpu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
> +    cpu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
> +    cpu_fprintf(f, "SREG:    [ %c %c %c %c %c %c %c %c ]\n",
> +                        env->sregI ? 'I' : '-',
> +                        env->sregT ? 'T' : '-',
> +                        env->sregH ? 'H' : '-',
> +                        env->sregS ? 'S' : '-',
> +                        env->sregV ? 'V' : '-',
> +                        env->sregN ? '-' : 'N', /*  Zf has negative logic   */
> +                        env->sregZ ? 'Z' : '-',
> +                        env->sregC ? 'I' : '-');
> +
> +    cpu_fprintf(f, "\n");
> +    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
> +        cpu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
> +
> +        if ((i % 8) == 7) {
> +            cpu_fprintf(f, "\n");
> +        }
> +    }
> +
> +    cpu_fprintf(f, "\n");
> +    for (i = 0; i < ARRAY_SIZE(env->io); i++) {
> +        cpu_fprintf(f, "IO[%02d]: %02x   ", i, env->io[i]);
> +
> +        if ((i % 8) == 7) {
> +            cpu_fprintf(f, "\n");
> +        }
> +    }
> +}
> +
> diff --git a/target-avr/translate.h b/target-avr/translate.h
> new file mode 100644
> index 0000000..8dc0e16
> --- /dev/null
> +++ b/target-avr/translate.h
> @@ -0,0 +1,116 @@
> +/*
> + *  QEMU AVR CPU
> + *
> + *  Copyright (c) 2016 Michael Rolnik
> + *
> + *  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>
> + */
> +
> +#ifndef AVR_TRANSLATE_H_
> +#define AVR_TRANSLATE_H_
> +
> +#include "qemu/osdep.h"
> +
> +#include "tcg/tcg.h"
> +#include "cpu.h"
> +#include "exec/exec-all.h"
> +#include "disas/disas.h"
> +#include "tcg-op.h"
> +#include "exec/cpu_ldst.h"
> +
> +#include "exec/helper-proto.h"
> +#include "exec/helper-gen.h"
> +#include "exec/log.h"
> +
> +extern TCGv_env cpu_env;
> +
> +extern TCGv     cpu_pc;
> +
> +extern TCGv     cpu_Cf;
> +extern TCGv     cpu_Zf;
> +extern TCGv     cpu_Nf;
> +extern TCGv     cpu_Vf;
> +extern TCGv     cpu_Sf;
> +extern TCGv     cpu_Hf;
> +extern TCGv     cpu_Tf;
> +extern TCGv     cpu_If;
> +
> +extern TCGv     cpu_rampD;
> +extern TCGv     cpu_rampX;
> +extern TCGv     cpu_rampY;
> +extern TCGv     cpu_rampZ;
> +
> +extern TCGv     cpu_io[64];
> +extern TCGv     cpu_r[32];
> +extern TCGv     cpu_eind;
> +extern TCGv     cpu_sp;
> +
> +enum {
> +    BS_NONE     = 0,    /*  Nothing special (none of the below          */

Missing ')' in comment.

> +    BS_STOP     = 1,    /*  We want to stop translation for any reason  */
> +    BS_BRANCH   = 2,    /*  A branch condition is reached               */
> +    BS_EXCP     = 3,    /*  An exception condition is reached           */
> +};
> +
> +uint32_t    get_opcode(uint8_t const *code, unsigned bitBase, unsigned bitSize);
> +
> +typedef struct DisasContext DisasContext;
> +typedef struct InstInfo     InstInfo;
> +
> +typedef int (*translate_function_t)(CPUAVRState *env, DisasContext *ctx,
> +                                        uint32_t opcode);
> +struct InstInfo {
> +    target_long                 cpc;
> +    target_long                 npc;
> +    uint32_t                    opcode;
> +    translate_function_t        translate;
> +    unsigned                    length;
> +};
> +
> +/*This is the state at translation time.  */
> +struct DisasContext {
> +    struct TranslationBlock    *tb;
> +
> +    InstInfo                    inst[2];/*  two consequitive instructions   */

"consecutive"

> +
> +    /*Routine used to access memory */
> +    int                         memidx;
> +    int                         bstate;
> +    int                         singlestep;
> +};
> +
> +void avr_decode(uint32_t pc, uint32_t *length, uint32_t opcode,
> +                        translate_function_t *translate);
> +
> +static inline void  gen_goto_tb(CPUAVRState *env, DisasContext *ctx,
> +                        int n, target_ulong dest)
> +{
> +    TranslationBlock   *tb;
> +
> +    tb      = ctx->tb;
> +
> +    if (ctx->singlestep == 0) {
> +        tcg_gen_goto_tb(n);
> +        tcg_gen_movi_i32(cpu_pc, dest);
> +        tcg_gen_exit_tb((uintptr_t)tb + n);
> +    } else {
> +        tcg_gen_movi_i32(cpu_pc, dest);
> +        gen_helper_debug(cpu_env);
> +        tcg_gen_exit_tb(0);
> +    }
> +}
> +
> +#endif
> +
> --
> 2.4.9 (Apple Git-60)
>


thanks
-- PMM
diff mbox

Patch

diff --git a/arch_init.c b/arch_init.c
index fa05973..be6e6de 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -80,6 +80,8 @@  int graphic_depth = 32;
 #define QEMU_ARCH QEMU_ARCH_UNICORE32
 #elif defined(TARGET_TRICORE)
 #define QEMU_ARCH QEMU_ARCH_TRICORE
+#elif defined(TARGET_AVR)
+#define QEMU_ARCH QEMU_ARCH_AVR
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
diff --git a/configure b/configure
index 6ffa4a8..84a4470 100755
--- a/configure
+++ b/configure
@@ -5638,6 +5638,8 @@  case "$target_name" in
   x86_64)
     TARGET_BASE_ARCH=i386
   ;;
+  avr)
+  ;;
   alpha)
   ;;
   arm|armeb)
@@ -5834,6 +5836,9 @@  disas_config() {
 
 for i in $ARCH $TARGET_BASE_ARCH ; do
   case "$i" in
+  avr)
+    disas_config "AVR"
+  ;;
   alpha)
     disas_config "ALPHA"
   ;;
diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak
new file mode 100644
index 0000000..003465d
--- /dev/null
+++ b/default-configs/avr-softmmu.mak
@@ -0,0 +1,21 @@ 
+#
+#  QEMU AVR CPU
+#
+#  Copyright (c) 2016 Michael Rolnik
+#
+#  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>
+#
+
+# Default configuration for avr-softmmu
diff --git a/include/disas/bfd.h b/include/disas/bfd.h
index 8a3488c..8ccd108 100644
--- a/include/disas/bfd.h
+++ b/include/disas/bfd.h
@@ -213,6 +213,12 @@  enum bfd_architecture
 #define bfd_mach_m32r          0  /* backwards compatibility */
   bfd_arch_mn10200,    /* Matsushita MN10200 */
   bfd_arch_mn10300,    /* Matsushita MN10300 */
+  bfd_arch_avr,       /* Atmel AVR microcontrollers.  */
+#define bfd_mach_avr1          1
+#define bfd_mach_avr2          2
+#define bfd_mach_avr3          3
+#define bfd_mach_avr4          4
+#define bfd_mach_avr5          5
   bfd_arch_cris,       /* Axis CRIS */
 #define bfd_mach_cris_v0_v10   255
 #define bfd_mach_cris_v32      32
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index d690dfa..8c75777 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -23,6 +23,7 @@  enum {
     QEMU_ARCH_UNICORE32 = (1 << 14),
     QEMU_ARCH_MOXIE = (1 << 15),
     QEMU_ARCH_TRICORE = (1 << 16),
+    QEMU_ARCH_AVR = (1 << 17),
 };
 
 extern const uint32_t arch_type;
diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs
new file mode 100644
index 0000000..2a10104
--- /dev/null
+++ b/target-avr/Makefile.objs
@@ -0,0 +1,23 @@ 
+#
+#  QEMU AVR CPU
+#
+#  Copyright (c) 2016 Michael Rolnik
+#
+#  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>
+#
+
+obj-y   += translate.o cpu.o helper.o
+obj-y   += gdbstub.o
+obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-avr/cpu-qom.h b/target-avr/cpu-qom.h
new file mode 100644
index 0000000..ba60988
--- /dev/null
+++ b/target-avr/cpu-qom.h
@@ -0,0 +1,85 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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>
+ */
+
+#ifndef QEMU_AVR_CPU_QOM_H
+#define QEMU_AVR_CPU_QOM_H
+
+#include "qom/cpu.h"
+
+#define TYPE_AVR_CPU            "avr"
+
+#define AVR_CPU_CLASS(klass)    \
+                    OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU)
+#define AVR_CPU(obj)            \
+                    OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU)
+#define AVR_CPU_GET_CLASS(obj)  \
+                    OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_AVR_CPU)
+
+/**
+*  AVRCPUClass:
+*  @parent_realize: The parent class' realize handler.
+*  @parent_reset: The parent class' reset handler.
+*  @vr: Version Register value.
+*
+*  A AVR CPU model.
+*/
+typedef struct AVRCPUClass {
+    CPUClass        parent_class;
+
+    DeviceRealize   parent_realize;
+    void (*parent_reset)(CPUState *cpu);
+} AVRCPUClass;
+
+/**
+*  AVRCPU:
+*  @env: #CPUAVRState
+*
+*  A AVR CPU.
+*/
+typedef struct AVRCPU {
+    /*< private >*/
+    CPUState        parent_obj;
+    /*< public >*/
+
+    CPUAVRState     env;
+} AVRCPU;
+
+static inline AVRCPU   *avr_env_get_cpu(CPUAVRState *env)
+{
+    return container_of(env, AVRCPU, env);
+}
+
+#define ENV_GET_CPU(e)          CPU(avr_env_get_cpu(e))
+#define ENV_OFFSET              offsetof(AVRCPU, env)
+
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vms_avr_cpu;
+#endif
+
+void avr_cpu_do_interrupt(CPUState *cpu);
+bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void avr_cpu_dump_state(CPUState *cs, FILE *f,
+                            fprintf_function cpu_fprintf, int flags);
+hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int avr_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
+#endif
+
diff --git a/target-avr/cpu.c b/target-avr/cpu.c
new file mode 100644
index 0000000..7e8d34b
--- /dev/null
+++ b/target-avr/cpu.c
@@ -0,0 +1,307 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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 "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "migration/vmstate.h"
+#include "machine.h"
+
+static void avr_cpu_set_pc(CPUState *cs, vaddr value)
+{
+    AVRCPU   *cpu = AVR_CPU(cs);
+
+    cpu->env.pc_w = value / 2;    /*  internally PC points to words   */
+}
+
+static bool avr_cpu_has_work(CPUState *cs)
+{
+    AVRCPU *cpu = AVR_CPU(cs);
+    CPUAVRState *env = &cpu->env;
+
+    return      (cs->interrupt_request
+                &   (CPU_INTERRUPT_HARD
+                    | CPU_INTERRUPT_RESET))
+            &&  cpu_interrupts_enabled(env);
+}
+
+static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+    AVRCPU      *cpu = AVR_CPU(cs);
+    CPUAVRState *env = &cpu->env;
+
+    env->pc_w = tb->pc / 2;   /*  internally PC points to words   */
+}
+
+static void avr_cpu_reset(CPUState *s)
+{
+    AVRCPU *cpu = AVR_CPU(s);
+    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
+    CPUAVRState *env = &cpu->env;
+
+    mcc->parent_reset(s);
+
+    env->pc_w = 0;
+    env->sregI = 1;
+    env->sregC = 0;
+    env->sregZ = 0;
+    env->sregN = 0;
+    env->sregV = 0;
+    env->sregS = 0;
+    env->sregH = 0;
+    env->sregT = 0;
+
+    env->rampD = 0;
+    env->rampX = 0;
+    env->rampY = 0;
+    env->rampZ = 0;
+    env->eind = 0;
+    env->sp = 0;
+
+    memset(env->io, 0, sizeof(env->io));
+    memset(env->r, 0, sizeof(env->r));
+
+    tlb_flush(s, 1);
+}
+
+static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
+{
+    info->mach = bfd_arch_avr;
+    info->print_insn = NULL;
+}
+
+static void avr_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+    CPUState *cs = CPU(dev);
+    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev);
+
+    qemu_init_vcpu(cs);
+    cpu_reset(cs);
+
+    mcc->parent_realize(dev, errp);
+}
+
+static void avr_cpu_set_int(void *opaque, int irq, int level)
+{
+    AVRCPU *cpu = opaque;
+    CPUAVRState *env = &cpu->env;
+    CPUState *cs = CPU(cpu);
+
+    uint64_t mask = (1ull << irq);
+    if (level) {
+        env->intsrc |=  mask;
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+    } else {
+        env->intsrc &= ~mask;
+        if (env->intsrc == 0) {
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+        }
+    }
+}
+
+static void avr_cpu_initfn(Object *obj)
+{
+    CPUState *cs = CPU(obj);
+    AVRCPU *cpu = AVR_CPU(obj);
+    static int inited;
+
+    cs->env_ptr = &cpu->env;
+    cpu_exec_init(cs, &error_abort);
+
+#ifndef CONFIG_USER_ONLY
+    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 37);
+#endif
+
+    if (tcg_enabled() && !inited) {
+        inited = 1;
+        avr_translate_init();
+    }
+}
+
+static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+    char *typename;
+    char **cpuname;
+
+    if (!cpu_model) {
+        return NULL;
+    }
+
+    cpuname = g_strsplit(cpu_model, ",", 1);
+    typename = g_strdup_printf("%s-" TYPE_AVR_CPU, cpuname[0]);
+    oc = object_class_by_name(typename);
+
+    g_strfreev(cpuname);
+    g_free(typename);
+
+    if (!oc
+        ||  !object_class_dynamic_cast(oc, TYPE_AVR_CPU)
+        ||  object_class_is_abstract(oc)) {
+        return NULL;
+    }
+
+    return oc;
+}
+
+static void avr_cpu_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    CPUClass *cc = CPU_CLASS(oc);
+    AVRCPUClass *mcc = AVR_CPU_CLASS(oc);
+
+    mcc->parent_realize = dc->realize;
+    dc->realize = avr_cpu_realizefn;
+
+    mcc->parent_reset = cc->reset;
+    cc->reset = avr_cpu_reset;
+
+    cc->class_by_name = avr_cpu_class_by_name;
+
+    cc->has_work = avr_cpu_has_work;
+    cc->do_interrupt = avr_cpu_do_interrupt;
+    cc->cpu_exec_interrupt = avr_cpu_exec_interrupt;
+    cc->dump_state = avr_cpu_dump_state;
+    cc->set_pc = avr_cpu_set_pc;
+#if !defined(CONFIG_USER_ONLY)
+    cc->memory_rw_debug = avr_cpu_memory_rw_debug;
+#endif
+#ifdef CONFIG_USER_ONLY
+    cc->handle_mmu_fault = avr_cpu_handle_mmu_fault;
+#else
+    cc->get_phys_page_debug = avr_cpu_get_phys_page_debug;
+    cc->vmsd = &vms_avr_cpu;
+#endif
+    cc->disas_set_info = avr_cpu_disas_set_info;
+    cc->synchronize_from_tb = avr_cpu_synchronize_from_tb;
+    cc->gdb_read_register = avr_cpu_gdb_read_register;
+    cc->gdb_write_register = avr_cpu_gdb_write_register;
+    cc->gdb_num_core_regs = 35;
+
+    /*
+     * Reason: avr_cpu_initfn() calls cpu_exec_init(), which saves
+     * the object in cpus -> dangling pointer after final
+     * object_unref().
+     */
+    dc->cannot_destroy_with_object_finalize_yet = true;
+}
+
+static void avr_any_initfn(Object *obj)
+{
+    /* Set cpu feature flags */
+}
+
+typedef struct AVRCPUInfo {
+    const char     *name;
+    void (*initfn)(Object *obj);
+} AVRCPUInfo;
+
+static const AVRCPUInfo avr_cpus[] = {
+    {   .name = "any",      .initfn = avr_any_initfn },
+};
+
+static gint avr_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+    ObjectClass *class_a = (ObjectClass *)a;
+    ObjectClass *class_b = (ObjectClass *)b;
+    const char *name_a;
+    const char *name_b;
+
+    name_a = object_class_get_name(class_a);
+    name_b = object_class_get_name(class_b);
+    if (strcmp(name_a, "any-" TYPE_AVR_CPU) == 0) {
+        return 1;
+    } else if (strcmp(name_b, "any-" TYPE_AVR_CPU) == 0) {
+        return -1;
+    } else {
+        return strcmp(name_a, name_b);
+    }
+}
+
+static void avr_cpu_list_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    CPUListState *s = user_data;
+    const char *typename;
+    char *name;
+
+    typename = object_class_get_name(oc);
+    name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_AVR_CPU));
+    (*s->cpu_fprintf)(s->file, "  %s\n", name);
+    g_free(name);
+}
+
+void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    CPUListState s = {
+        .file = f,
+        .cpu_fprintf = cpu_fprintf,
+    };
+    GSList *list;
+
+    list = object_class_get_list(TYPE_AVR_CPU, false);
+    list = g_slist_sort(list, avr_cpu_list_compare);
+    (*cpu_fprintf)(f, "Available CPUs:\n");
+    g_slist_foreach(list, avr_cpu_list_entry, &s);
+    g_slist_free(list);
+}
+
+AVRCPU *cpu_avr_init(const char *cpu_model)
+{
+    return AVR_CPU(cpu_generic_init(TYPE_AVR_CPU, cpu_model));
+}
+
+static void cpu_register(const AVRCPUInfo *info)
+{
+    TypeInfo type_info = {
+        .parent = TYPE_AVR_CPU,
+        .instance_size = sizeof(AVRCPU),
+        .instance_init = info->initfn,
+        .class_size = sizeof(AVRCPUClass),
+    };
+
+    type_info.name = g_strdup_printf("%s-" TYPE_AVR_CPU, info->name);
+    type_register(&type_info);
+    g_free((void *)type_info.name);
+}
+
+static const TypeInfo avr_cpu_type_info = {
+    .name = TYPE_AVR_CPU,
+    .parent = TYPE_CPU,
+    .instance_size = sizeof(AVRCPU),
+    .instance_init = avr_cpu_initfn,
+    .class_size = sizeof(AVRCPUClass),
+    .class_init = avr_cpu_class_init,
+    .abstract = true,
+};
+
+static void avr_cpu_register_types(void)
+{
+    int i;
+    type_register_static(&avr_cpu_type_info);
+
+    for (i = 0; i < ARRAY_SIZE(avr_cpus); i++) {
+        cpu_register(&avr_cpus[i]);
+    }
+}
+
+type_init(avr_cpu_register_types)
+
diff --git a/target-avr/cpu.h b/target-avr/cpu.h
new file mode 100644
index 0000000..6bc8b86
--- /dev/null
+++ b/target-avr/cpu.h
@@ -0,0 +1,179 @@ 
+ /*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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>
+ */
+
+#if !defined(CPU_AVR_H)
+#define CPU_AVR_H
+
+#include "qemu-common.h"
+
+#define TARGET_LONG_BITS            32
+
+#define CPUArchState struct CPUAVRState
+
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat.h"
+
+/*
+    TARGET_PAGE_BITS cannot be more than 8 bits because
+    1.  all IO registers occupy [0x0000 .. 0x00ff] address range, and they
+        should be implemented as a device and not memory
+    2.  SRAM starts at the address 0x0100
+*/
+#define TARGET_PAGE_BITS            8
+#define TARGET_PHYS_ADDR_SPACE_BITS 24
+#define TARGET_VIRT_ADDR_SPACE_BITS 24
+#define NB_MMU_MODES                2
+
+#define MMU_CODE_IDX                0
+#define MMU_DATA_IDX                1
+
+#define EXCP_RESET                  1
+#define EXCP_INT(n)                 (EXCP_RESET + (n) + 1)
+
+#define PHYS_ADDR_MASK              0xfff00000
+
+#define PHYS_BASE_CODE              0x00000000
+#define PHYS_BASE_DATA              0x00800000
+#define PHYS_BASE_REGS              0x10000000
+
+#define VIRT_BASE_CODE              0x00000000
+#define VIRT_BASE_DATA              0x00000000
+#define VIRT_BASE_REGS              0x00000000
+
+/*
+    there are three groups of registers
+    1. CPU regs     - accessable by LD/ST and CPU itself
+    2. CPU IO regs  - accessable by LD/ST and IN/OUT
+    3. EXT IO regs  - accessable by LD/ST
+*/
+#define AVR_CPU_REGS                0x0020
+#define AVR_CPU_IO_REGS             0x0040
+#define AVR_EXT_IO_REGS             0x00a0
+#define AVR_IO_REGS                 (AVR_CPU_IO_REGS + AVR_EXT_IO_REGS)
+#define AVR_REGS                    (AVR_IO_REGS + AVR_CPU_REGS)
+
+#define AVR_CPU_REGS_BASE           0x0000
+#define AVR_CPU_IO_REGS_BASE        (AVR_CPU_REGS_BASE + AVR_CPU_REGS)
+#define AVR_EXT_IO_REGS_BASE        (AVR_CPU_IO_REGS_BASE + AVR_CPU_IO_REGS)
+
+#define AVR_CPU_REGS_LAST           (AVR_CPU_REGS_BASE + AVR_CPU_REGS - 1)
+#define AVR_CPU_IO_REGS_LAST        (AVR_CPU_IO_REGS_BASE + AVR_CPU_IO_REGS - 1)
+#define AVR_EXT_IO_REGS_LAST        (AVR_EXT_IO_REGS_BASE + AVR_EXT_IO_REGS - 1)
+
+typedef struct CPUAVRState CPUAVRState;
+
+struct CPUAVRState {
+    uint32_t        pc_w;   /*   0x003fffff up to 22 bits           */
+
+    uint32_t        sregC;  /*   0x00000001 1 bits                  */
+    uint32_t        sregZ;  /*   0x0000ffff 16 bits, negative logic */
+    uint32_t        sregN;  /*   0x00000001 1 bits                  */
+    uint32_t        sregV;  /*   0x00000001 1 bits                  */
+    uint32_t        sregS;  /*   0x00000001 1 bits                  */
+    uint32_t        sregH;  /*   0x00000001 1 bits                  */
+    uint32_t        sregT;  /*   0x00000001 1 bits                  */
+    uint32_t        sregI;  /*   0x00000001 1 bits                  */
+
+    uint32_t        rampD;  /*   0x00ff0000 8 bits                  */
+    uint32_t        rampX;  /*   0x00ff0000 8 bits                  */
+    uint32_t        rampY;  /*   0x00ff0000 8 bits                  */
+    uint32_t        rampZ;  /*   0x00ff0000 8 bits                  */
+    uint32_t        eind;   /*   0x00ff0000 8 bits                  */
+
+    uint32_t        io[AVR_CPU_IO_REGS];
+                            /*   8 bits each                        */
+    uint32_t        r[AVR_CPU_REGS];
+                            /*   8 bits each                        */
+    uint32_t        sp;     /*   16 bits                            */
+
+    uint64_t        intsrc; /*  interrupt sources                   */
+
+    /* Those resources are used only in QEMU core */
+    CPU_COMMON
+};
+
+#define cpu_list            avr_cpu_list
+#define cpu_signal_handler  cpu_avr_signal_handler
+
+#include "exec/cpu-all.h"
+#include "cpu-qom.h"
+
+static inline int cpu_mmu_index(CPUAVRState *env, bool ifetch)
+{
+    return  ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
+}
+
+void avr_translate_init(void);
+
+AVRCPU *cpu_avr_init(const char *cpu_model);
+
+#define cpu_init(cpu_model) CPU(cpu_avr_init(cpu_model))
+
+void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_avr_exec(CPUState *cpu);
+int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc);
+int avr_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+                                int mmu_idx);
+int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
+                                int len, bool is_write);
+
+static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc,
+                                target_ulong *cs_base, uint32_t *pflags)
+{
+    *pc = env->pc_w * 2;
+    *cs_base = 0;
+    *pflags = 0;
+}
+
+static inline int cpu_interrupts_enabled(CPUAVRState *env1)
+{
+    return  env1->sregI != 0;
+}
+
+static inline uint8_t cpu_get_sreg(CPUAVRState *env)
+{
+    uint8_t sreg;
+    sreg = (env->sregC & 0x01) << 0
+            | (env->sregZ == 0 ? 1 : 0) << 1
+            | (env->sregN) << 2
+            | (env->sregV) << 3
+            | (env->sregS) << 4
+            | (env->sregH) << 5
+            | (env->sregT) << 6
+            | (env->sregI) << 7;
+    return  sreg;
+}
+
+static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg)
+{
+    env->sregC = (sreg >> 0) & 0x01;
+    env->sregZ = (sreg >> 1) & 0x01 ? 0 : 1;
+    env->sregN = (sreg >> 2) & 0x01;
+    env->sregV = (sreg >> 3) & 0x01;
+    env->sregS = (sreg >> 4) & 0x01;
+    env->sregH = (sreg >> 5) & 0x01;
+    env->sregT = (sreg >> 6) & 0x01;
+    env->sregI = (sreg >> 7) & 0x01;
+}
+
+#include "exec/exec-all.h"
+
+#endif /* !defined (CPU_AVR_H) */
+
diff --git a/target-avr/gdbstub.c b/target-avr/gdbstub.c
new file mode 100644
index 0000000..e05b7e1
--- /dev/null
+++ b/target-avr/gdbstub.c
@@ -0,0 +1,85 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+
+int avr_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    AVRCPU *cpu = AVR_CPU(cs);
+    CPUAVRState *env = &cpu->env;
+
+    /*  R */
+    if (n < 32) {
+        return gdb_get_reg8(mem_buf, env->r[n]);
+    }
+
+    /*  SREG */
+    if (n == 32) {
+        uint8_t sreg = cpu_get_sreg(env);
+
+        return gdb_get_reg8(mem_buf, sreg);
+    }
+
+    /*  SP */
+    if (n == 33) {
+        return  gdb_get_reg16(mem_buf, env->sp & 0x0000ffff);
+    }
+
+    /*  PC */
+    if (n == 34) {
+        return  gdb_get_reg32(mem_buf, env->pc_w * 2);
+    }
+
+    return 0;
+}
+
+int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    AVRCPU *cpu = AVR_CPU(cs);
+    CPUAVRState *env = &cpu->env;
+    uint16_t tmp = ldl_p(mem_buf);
+
+    /*  R */
+    if (n < 32) {
+        env->r[n] = tmp;
+    }
+
+    /*  SREG */
+    if (n == 32) {
+        cpu_set_sreg(env, tmp);
+    }
+
+    /*  SP */
+    if (n == 33) {
+        env->sp = tmp;
+        return  2;
+    }
+
+    /*  PC */
+    if (n == 34) {
+        env->pc_w = tmp / 2;
+        return  4;
+    }
+
+    return 1;
+}
+
diff --git a/target-avr/helper.c b/target-avr/helper.c
new file mode 100644
index 0000000..ffc9378
--- /dev/null
+++ b/target-avr/helper.c
@@ -0,0 +1,87 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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 "qemu/osdep.h"
+
+#include "cpu.h"
+#include "hw/irq.h"
+#include "include/hw/sysbus.h"
+#include "include/sysemu/sysemu.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+
+bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    return  false;
+}
+
+void avr_cpu_do_interrupt(CPUState *cs)
+{
+}
+
+int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf,
+                                int len, bool is_write)
+{
+    return  cpu_memory_rw_debug(cs, addr, buf, len, is_write);
+}
+
+hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+    return  addr;   /*  I assume 1:1 address correspondance */
+}
+
+int avr_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx)
+{
+    cs->exception_index = EXCP_DEBUG;
+    cpu_dump_state(cs, stderr, fprintf, 0);
+    return 1;
+}
+
+void tlb_fill(CPUState *cs, target_ulong vaddr, MMUAccessType access_type,
+                                int mmu_idx, uintptr_t retaddr)
+{
+    target_ulong page_size = TARGET_PAGE_SIZE;
+    int prot = 0;
+    MemTxAttrs attrs = {};
+    uint32_t paddr;
+
+    vaddr &= TARGET_PAGE_MASK;
+
+    if (mmu_idx == MMU_CODE_IDX) {
+        paddr = PHYS_BASE_CODE + vaddr;
+        prot = PAGE_READ | PAGE_EXEC;
+    } else {
+        paddr = PHYS_BASE_DATA + vaddr;
+        prot = PAGE_READ | PAGE_WRITE;
+    }
+
+    tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size);
+}
+
+void helper_debug(CPUAVRState *env)
+{
+    CPUState *cs = CPU(avr_env_get_cpu(env));
+
+    cs->exception_index = EXCP_DEBUG;
+    cpu_loop_exit(cs);
+}
+
diff --git a/target-avr/helper.h b/target-avr/helper.h
new file mode 100644
index 0000000..c60ac3e
--- /dev/null
+++ b/target-avr/helper.h
@@ -0,0 +1,22 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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>
+ */
+
+DEF_HELPER_1(debug, void, env)
+
diff --git a/target-avr/machine.c b/target-avr/machine.c
new file mode 100644
index 0000000..5c8049e
--- /dev/null
+++ b/target-avr/machine.c
@@ -0,0 +1,117 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/hw.h"
+#include "cpu.h"
+#include "hw/boards.h"
+#include "machine.h"
+#include "migration/qemu-file.h"
+
+static int get_sreg(QEMUFile *f, void *opaque, size_t size)
+{
+    CPUAVRState *env = opaque;
+    uint8_t sreg;
+
+    qemu_get_8s(f, &sreg);
+    cpu_set_sreg(env, sreg);
+    return 0;
+}
+
+static void put_sreg(QEMUFile *f, void *opaque, size_t size)
+{
+    CPUAVRState *env = opaque;
+    uint8_t sreg = cpu_get_sreg(env);
+
+    qemu_put_8s(f, &sreg);
+}
+
+static const VMStateInfo vms_sreg = {
+    .name = "sreg",
+    .get  = get_sreg,
+    .put  = put_sreg,
+};
+
+static int get_segment(QEMUFile *f, void *opaque, size_t size)
+{
+    uint32_t *ramp = opaque;
+    uint8_t temp = *ramp >> 16;
+
+    qemu_get_8s(f, &temp);
+    return 0;
+}
+
+static void put_segment(QEMUFile *f, void *opaque, size_t size)
+{
+    uint32_t *ramp = opaque;
+    uint8_t temp = 0;
+
+    qemu_put_8s(f, &temp);
+    *ramp = ((uint32_t)temp) << 16;
+}
+
+static const VMStateInfo vms_rampD = {
+    .name = "rampD",
+    .get  = get_segment,
+    .put  = put_segment,
+};
+static const VMStateInfo vms_rampX = {
+    .name = "rampX",
+    .get  = get_segment,
+    .put  = put_segment,
+};
+static const VMStateInfo vms_rampY = {
+    .name = "rampY",
+    .get  = get_segment,
+    .put  = put_segment,
+};
+static const VMStateInfo vms_rampZ = {
+    .name = "rampZ",
+    .get  = get_segment,
+    .put  = put_segment,
+};
+static const VMStateInfo vms_eind = {
+    .name = "eind",
+    .get  = get_segment,
+    .put  = put_segment,
+};
+
+const VMStateDescription vms_avr_cpu = {
+    .name               = "cpu",
+    .version_id         = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(env.pc_w, AVRCPU),
+        VMSTATE_UINT32(env.sp, AVRCPU),
+
+        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, AVR_CPU_REGS),
+        VMSTATE_UINT32_ARRAY(env.io, AVRCPU, AVR_CPU_IO_REGS),
+
+        VMSTATE_SINGLE_TEST(env, AVRCPU, NULL, 0, vms_sreg, CPUAVRState),
+        VMSTATE_SINGLE_TEST(env.rampD, AVRCPU, NULL, 0, vms_rampD, uint32_t),
+        VMSTATE_SINGLE_TEST(env.rampX, AVRCPU, NULL, 0, vms_rampX, uint32_t),
+        VMSTATE_SINGLE_TEST(env.rampY, AVRCPU, NULL, 0, vms_rampY, uint32_t),
+        VMSTATE_SINGLE_TEST(env.rampZ, AVRCPU, NULL, 0, vms_rampZ, uint32_t),
+        VMSTATE_SINGLE_TEST(env.eind, AVRCPU, NULL, 0, vms_eind, uint32_t),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
diff --git a/target-avr/machine.h b/target-avr/machine.h
new file mode 100644
index 0000000..cc22888
--- /dev/null
+++ b/target-avr/machine.h
@@ -0,0 +1,22 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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>
+ */
+
+extern const VMStateDescription vmstate_avr_cpu;
+
diff --git a/target-avr/translate.c b/target-avr/translate.c
new file mode 100644
index 0000000..ce87c11
--- /dev/null
+++ b/target-avr/translate.c
@@ -0,0 +1,283 @@ 
+/*
+ *  QEMU AVR CPU
+ *
+ *  Copyright (c) 2016 Michael Rolnik
+ *
+ *  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 "translate.h"
+
+TCGv_env cpu_env;
+
+TCGv     cpu_pc;
+
+TCGv     cpu_Cf;
+TCGv     cpu_Zf;
+TCGv     cpu_Nf;
+TCGv     cpu_Vf;
+TCGv     cpu_Sf;
+TCGv     cpu_Hf;
+TCGv     cpu_Tf;
+TCGv     cpu_If;
+
+TCGv     cpu_rampD;
+TCGv     cpu_rampX;
+TCGv     cpu_rampY;
+TCGv     cpu_rampZ;
+
+TCGv     cpu_io[64];
+TCGv     cpu_r[32];
+TCGv     cpu_eind;
+TCGv     cpu_sp;
+
+#include "exec/gen-icount.h"
+#define REG(x)  (cpu_r[x])
+
+void avr_translate_init(void)
+{
+    int i;
+    static int done_init;
+
+    if (done_init) {
+        return;
+    }
+#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x)
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w),  "pc");
+    cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf");
+    cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf");
+    cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf");
+    cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf");
+    cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf");
+    cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf");
+    cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf");
+    cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If");
+    cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD");
+    cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX");
+    cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY");
+    cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ");
+    cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind),  "eind");
+    cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp),    "sp");
+
+    for (i = 0; i < 64; i++) {
+        char    name[16];
+
+        sprintf(name, "io[%d]", i);
+
+        cpu_io[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(io[i]), name);
+    }
+    for (i = 0; i < 32; i++) {
+        char    name[16];
+
+        sprintf(name, "r[%d]", i);
+
+        cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), name);
+    }
+
+    done_init = 1;
+}
+
+static int translate_nop(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+    return BS_NONE;
+}
+
+void avr_decode(uint32_t pc, uint32_t *length, uint32_t opcode,
+                        translate_function_t *translate)
+{
+    *length = 32;
+    *translate = &translate_nop;
+}
+
+static void decode_opc(AVRCPU *cpu, DisasContext *ctx, InstInfo *inst)
+{
+    CPUAVRState        *env = &cpu->env;
+
+    inst->opcode = cpu_ldl_code(env, inst->cpc * 2);/*  pc points to words  */
+    inst->length = 16;
+    inst->translate = NULL;
+
+    /*  the following function looks onto the opcode as a string of bytes   */
+    avr_decode(inst->cpc, &inst->length, inst->opcode, &inst->translate);
+
+    if (inst->length == 16) {
+        inst->npc = inst->cpc + 1;
+        /*  get opcode as 16bit value   */
+        inst->opcode = inst->opcode & 0x0000ffff;
+    }
+    if (inst->length == 32) {
+        inst->npc = inst->cpc + 2;
+        /*  get opcode as 32bit value   */
+        inst->opcode = (inst->opcode << 16)
+                     | (inst->opcode >> 16);
+    }
+}
+
+/*generate intermediate code for basic block 'tb'.  */
+void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb)
+{
+    AVRCPU         *cpu = avr_env_get_cpu(env);
+    CPUState       *cs = CPU(cpu);
+    DisasContext    ctx;
+    target_ulong    pc_start;
+    int             num_insns,
+                    max_insns;
+    target_ulong    cpc;
+    target_ulong    npc;
+
+    pc_start = tb->pc / 2;
+    ctx.tb = tb;
+    ctx.memidx = 0;
+    ctx.bstate = BS_NONE;
+    ctx.singlestep = cs->singlestep_enabled;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+    if (max_insns > TCG_MAX_INSNS) {
+        max_insns = TCG_MAX_INSNS;
+    }
+
+    gen_tb_start(tb);
+
+    /*  decode first instruction    */
+    ctx.inst[0].cpc = pc_start;
+    decode_opc(cpu, &ctx, &ctx.inst[0]);
+    do {
+        /*  set curr/next PCs   */
+        cpc = ctx.inst[0].cpc;
+        npc = ctx.inst[0].npc;
+
+        /*  decode next instruction */
+        ctx.inst[1].cpc = ctx.inst[0].npc;
+        decode_opc(cpu, &ctx, &ctx.inst[1]);
+
+        /*  translate current instruction */
+        tcg_gen_insn_start(cpc);
+        num_insns++;
+
+        if (unlikely(cpu_breakpoint_test(cs, cpc * 2, BP_ANY))) {
+            tcg_gen_movi_i32(cpu_pc, cpc);
+            gen_helper_debug(cpu_env);
+            ctx.bstate = BS_EXCP;
+            /*The address covered by the breakpoint must be included in
+               [tb->pc, tb->pc + tb->size) in order to for it to be
+               properly cleared -- thus we increment the PC here so that
+               the logic setting tb->size below does the right thing.  */
+            goto done_generating;
+        }
+
+        ctx.bstate = ctx.inst[0].translate(env, &ctx, ctx.inst[0].opcode);
+
+        if (num_insns >= max_insns) {
+            break;      /* max translated instructions limit reached */
+        }
+        if (ctx.singlestep) {
+            break;      /* single step */
+        }
+        if ((cpc & (TARGET_PAGE_SIZE - 1)) == 0) {
+            break;      /* page boundary */
+        }
+
+        ctx.inst[0] = ctx.inst[1];  /*  make next inst curr */
+    } while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+    if (ctx.singlestep) {
+        if (ctx.bstate == BS_STOP || ctx.bstate == BS_NONE) {
+            tcg_gen_movi_tl(cpu_pc, npc);
+        }
+        gen_helper_debug(cpu_env);
+        tcg_gen_exit_tb(0);
+    } else {
+        switch (ctx.bstate) {
+        case BS_STOP:
+        case BS_NONE:
+            gen_goto_tb(env, &ctx, 0, npc);
+            break;
+        case BS_EXCP:
+            tcg_gen_exit_tb(0);
+            break;
+        default:
+            break;
+        }
+    }
+
+done_generating:
+    gen_tb_end(tb, num_insns);
+
+    tb->size = (npc - pc_start) * 2;
+    tb->icount = num_insns;
+}
+
+void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb,
+                            target_ulong *data)
+{
+    env->pc_w = data[0];
+}
+
+void avr_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
+                            int flags)
+{
+    AVRCPU *cpu = AVR_CPU(cs);
+    CPUAVRState *env = &cpu->env;
+    int i;
+
+    cpu_fprintf(f, "\n");
+    cpu_fprintf(f, "PC:    %06x\n", env->pc_w);
+    cpu_fprintf(f, "SP:      %04x\n", env->sp);
+    cpu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
+    cpu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
+    cpu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
+    cpu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
+    cpu_fprintf(f, "EIND:      %02x\n", env->eind);
+    cpu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
+    cpu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
+    cpu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
+    cpu_fprintf(f, "SREG:    [ %c %c %c %c %c %c %c %c ]\n",
+                        env->sregI ? 'I' : '-',
+                        env->sregT ? 'T' : '-',
+                        env->sregH ? 'H' : '-',
+                        env->sregS ? 'S' : '-',
+                        env->sregV ? 'V' : '-',
+                        env->sregN ? '-' : 'N', /*  Zf has negative logic   */
+                        env->sregZ ? 'Z' : '-',
+                        env->sregC ? 'I' : '-');
+
+    cpu_fprintf(f, "\n");
+    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
+        cpu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
+
+        if ((i % 8) == 7) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+
+    cpu_fprintf(f, "\n");
+    for (i = 0; i < ARRAY_SIZE(env->io); i++) {
+        cpu_fprintf(f, "IO[%02d]: %02x   ", i, env->io[i]);
+
+        if ((i % 8) == 7) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+}
+
diff --git a/target-avr/translate.h b/target-avr/translate.h
new file mode 100644
index 0000000..8dc0e16
--- /dev/null
+++ b/target-avr/translate.h
@@ -0,0 +1,116 @@ 
+/*
+ *  QEMU AVR CPU
+ *
+ *  Copyright (c) 2016 Michael Rolnik
+ *
+ *  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>
+ */
+
+#ifndef AVR_TRANSLATE_H_
+#define AVR_TRANSLATE_H_
+
+#include "qemu/osdep.h"
+
+#include "tcg/tcg.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "disas/disas.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+#include "exec/log.h"
+
+extern TCGv_env cpu_env;
+
+extern TCGv     cpu_pc;
+
+extern TCGv     cpu_Cf;
+extern TCGv     cpu_Zf;
+extern TCGv     cpu_Nf;
+extern TCGv     cpu_Vf;
+extern TCGv     cpu_Sf;
+extern TCGv     cpu_Hf;
+extern TCGv     cpu_Tf;
+extern TCGv     cpu_If;
+
+extern TCGv     cpu_rampD;
+extern TCGv     cpu_rampX;
+extern TCGv     cpu_rampY;
+extern TCGv     cpu_rampZ;
+
+extern TCGv     cpu_io[64];
+extern TCGv     cpu_r[32];
+extern TCGv     cpu_eind;
+extern TCGv     cpu_sp;
+
+enum {
+    BS_NONE     = 0,    /*  Nothing special (none of the below          */
+    BS_STOP     = 1,    /*  We want to stop translation for any reason  */
+    BS_BRANCH   = 2,    /*  A branch condition is reached               */
+    BS_EXCP     = 3,    /*  An exception condition is reached           */
+};
+
+uint32_t    get_opcode(uint8_t const *code, unsigned bitBase, unsigned bitSize);
+
+typedef struct DisasContext DisasContext;
+typedef struct InstInfo     InstInfo;
+
+typedef int (*translate_function_t)(CPUAVRState *env, DisasContext *ctx,
+                                        uint32_t opcode);
+struct InstInfo {
+    target_long                 cpc;
+    target_long                 npc;
+    uint32_t                    opcode;
+    translate_function_t        translate;
+    unsigned                    length;
+};
+
+/*This is the state at translation time.  */
+struct DisasContext {
+    struct TranslationBlock    *tb;
+
+    InstInfo                    inst[2];/*  two consequitive instructions   */
+
+    /*Routine used to access memory */
+    int                         memidx;
+    int                         bstate;
+    int                         singlestep;
+};
+
+void avr_decode(uint32_t pc, uint32_t *length, uint32_t opcode,
+                        translate_function_t *translate);
+
+static inline void  gen_goto_tb(CPUAVRState *env, DisasContext *ctx,
+                        int n, target_ulong dest)
+{
+    TranslationBlock   *tb;
+
+    tb      = ctx->tb;
+
+    if (ctx->singlestep == 0) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_i32(cpu_pc, dest);
+        tcg_gen_exit_tb((uintptr_t)tb + n);
+    } else {
+        tcg_gen_movi_i32(cpu_pc, dest);
+        gen_helper_debug(cpu_env);
+        tcg_gen_exit_tb(0);
+    }
+}
+
+#endif
+