diff mbox series

[v36,01/17] target/avr: Add outward facing interfaces and core CPU logic

Message ID 20191124050225.30351-2-mrolnik@gmail.com (mailing list archive)
State New, archived
Headers show
Series QEMU AVR 8 bit cores | expand

Commit Message

Michael Rolnik Nov. 24, 2019, 5:02 a.m. UTC
This includes:
- CPU data structures
- object model classes and functions
- migration functions
- GDB hooks

Co-developed-by: Michael Rolnik <mrolnik@gmail.com>
Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk>
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk>
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
---
 target/avr/cpu-param.h |  37 +++
 target/avr/cpu-qom.h   |  54 ++++
 target/avr/cpu.h       | 253 ++++++++++++++++++
 target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
 target/avr/gdbstub.c   |  85 ++++++
 target/avr/machine.c   | 121 +++++++++
 gdb-xml/avr-cpu.xml    |  49 ++++
 7 files changed, 1175 insertions(+)
 create mode 100644 target/avr/cpu-param.h
 create mode 100644 target/avr/cpu-qom.h
 create mode 100644 target/avr/cpu.h
 create mode 100644 target/avr/cpu.c
 create mode 100644 target/avr/gdbstub.c
 create mode 100644 target/avr/machine.c
 create mode 100644 gdb-xml/avr-cpu.xml

Comments

Aleksandar Markovic Nov. 24, 2019, 3:17 p.m. UTC | #1
On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com> wrote:

> This includes:
> - CPU data structures
> - object model classes and functions
> - migration functions
> - GDB hooks
>
> Co-developed-by: Michael Rolnik <mrolnik@gmail.com>
> Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Acked-by: Igor Mammedov <imammedo@redhat.com>
> ---
>  target/avr/cpu-param.h |  37 +++
>  target/avr/cpu-qom.h   |  54 ++++
>  target/avr/cpu.h       | 253 ++++++++++++++++++
>  target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
>  target/avr/gdbstub.c   |  85 ++++++
>  target/avr/machine.c   | 121 +++++++++
>  gdb-xml/avr-cpu.xml    |  49 ++++
>  7 files changed, 1175 insertions(+)
>  create mode 100644 target/avr/cpu-param.h
>  create mode 100644 target/avr/cpu-qom.h
>  create mode 100644 target/avr/cpu.h
>  create mode 100644 target/avr/cpu.c
>  create mode 100644 target/avr/gdbstub.c
>  create mode 100644 target/avr/machine.c
>  create mode 100644 gdb-xml/avr-cpu.xml
>
> diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
> new file mode 100644
> index 0000000000..ccd1ea3429
> --- /dev/null
> +++ b/target/avr/cpu-param.h
> @@ -0,0 +1,37 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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.
> + *


I think version 2 would be more fitting to QEMU ovarall license than 2.1
(see LICENCE file in QEMU root dir).

Peter, am I right or wrong regarding GPL 2 vs. 2.1 (My interpretation is
that 2 is the best "default" for new files)? The wording in "LICENSE" is
frankly not entirely clear, and I see many new files using 2.1.

Michael, please make sure that all files added by the serues hava an
appropriate and preferably consistent licence preamble.

Yours,
Aleksandar




> + * 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_CPU_PARAM_H
> +#define AVR_CPU_PARAM_H 1
> +
> +#define TARGET_LONG_BITS 32
> +/*
> + * 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
> +
> +
> +#endif
> diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h
> new file mode 100644
> index 0000000000..e28b58c897
> --- /dev/null
> +++ b/target/avr/cpu-qom.h
> @@ -0,0 +1,54 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_QOM_H
> +#define QEMU_AVR_QOM_H
> +
> +#include "hw/core/cpu.h"
> +
> +#define TYPE_AVR_CPU "avr-cpu"
> +
> +#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 {
> +    /*< private >*/
> +    CPUClass parent_class;
> +    /*< public >*/
> +    DeviceRealize parent_realize;
> +    void (*parent_reset)(CPUState *cpu);
> +} AVRCPUClass;
> +
> +typedef struct AVRCPU AVRCPU;
> +
> +
> +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */
> diff --git a/target/avr/cpu.h b/target/avr/cpu.h
> new file mode 100644
> index 0000000000..ed9218af5f
> --- /dev/null
> +++ b/target/avr/cpu.h
> @@ -0,0 +1,253 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_H
> +#define QEMU_AVR_CPU_H
> +
> +#include "cpu-qom.h"
> +#include "exec/cpu-defs.h"
> +
> +#define TCG_GUEST_DEFAULT_MO 0
> +
> +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU
> +
> +/*
> + * AVR has two memory spaces, data & code.
> + * e.g. both have 0 address
> + * ST/LD instructions access data space
> + * LPM/SPM and instruction fetching access code memory space
> + */
> +#define MMU_CODE_IDX 0
> +#define MMU_DATA_IDX 1
> +
> +#define EXCP_RESET 1
> +#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
> +
> +/* Number of CPU registers */
> +#define NO_CPU_REGISTERS 32
> +/* Number of IO registers accessible by ld/st/in/out */
> +#define NO_IO_REGISTERS 64
> +
> +/*
> + * Offsets of AVR memory regions in host memory space.
> + *
> + * This is needed because the AVR has separate code and data address
> + * spaces that both have start from zero but have to go somewhere in
> + * host memory.
> + *
> + * It's also useful to know where some things are, like the IO registers.
> + */
> +/* Flash program memory */
> +#define OFFSET_CODE 0x00000000
> +/* CPU registers, IO registers, and SRAM */
> +#define OFFSET_DATA 0x00800000
> +/* CPU registers specifically, these are mapped at the start of data */
> +#define OFFSET_CPU_REGISTERS OFFSET_DATA
> +/*
> + * IO registers, including status register, stack pointer, and memory
> + * mapped peripherals, mapped just after CPU registers
> + */
> +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS)
> +
> +enum avr_features {
> +    AVR_FEATURE_SRAM,
> +
> +    AVR_FEATURE_1_BYTE_PC,
> +    AVR_FEATURE_2_BYTE_PC,
> +    AVR_FEATURE_3_BYTE_PC,
> +
> +    AVR_FEATURE_1_BYTE_SP,
> +    AVR_FEATURE_2_BYTE_SP,
> +
> +    AVR_FEATURE_BREAK,
> +    AVR_FEATURE_DES,
> +    AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
> +
> +    AVR_FEATURE_EIJMP_EICALL,
> +    AVR_FEATURE_IJMP_ICALL,
> +    AVR_FEATURE_JMP_CALL,
> +
> +    AVR_FEATURE_ADIW_SBIW,
> +
> +    AVR_FEATURE_SPM,
> +    AVR_FEATURE_SPMX,
> +
> +    AVR_FEATURE_ELPMX,
> +    AVR_FEATURE_ELPM,
> +    AVR_FEATURE_LPMX,
> +    AVR_FEATURE_LPM,
> +
> +    AVR_FEATURE_MOVW,
> +    AVR_FEATURE_MUL,
> +    AVR_FEATURE_RAMPD,
> +    AVR_FEATURE_RAMPX,
> +    AVR_FEATURE_RAMPY,
> +    AVR_FEATURE_RAMPZ,
> +};
> +
> +typedef struct CPUAVRState CPUAVRState;
> +
> +struct CPUAVRState {
> +    uint32_t pc_w; /* 0x003fffff up to 22 bits */
> +
> +    uint32_t sregC; /* 0x00000001 1 bit */
> +    uint32_t sregZ; /* 0x00000001 1 bit */
> +    uint32_t sregN; /* 0x00000001 1 bit */
> +    uint32_t sregV; /* 0x00000001 1 bit */
> +    uint32_t sregS; /* 0x00000001 1 bit */
> +    uint32_t sregH; /* 0x00000001 1 bit */
> +    uint32_t sregT; /* 0x00000001 1 bit */
> +    uint32_t sregI; /* 0x00000001 1 bit */
> +
> +    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 r[NO_CPU_REGISTERS]; /* 8 bits each */
> +    uint32_t sp; /* 16 bits */
> +
> +    uint32_t skip; /* if set skip instruction */
> +
> +    uint64_t intsrc; /* interrupt sources */
> +    bool fullacc; /* CPU/MEM if true MEM only otherwise */
> +
> +    uint32_t features;
> +};
> +
> +/**
> + *  AVRCPU:
> + *  @env: #CPUAVRState
> + *
> + *  A AVR CPU.
> + */
> +typedef struct AVRCPU {
> +    /*< private >*/
> +    CPUState parent_obj;
> +    /*< public >*/
> +
> +    CPUNegativeOffsetState neg;
> +    CPUAVRState env;
> +} AVRCPU;
> +
> +#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);
> +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);
> +
> +static inline int avr_feature(CPUAVRState *env, int feature)
> +{
> +    return (env->features & (1U << feature)) != 0;
> +}
> +
> +static inline void avr_set_feature(CPUAVRState *env, int feature)
> +{
> +    env->features |= (1U << feature);
> +}
> +
> +#define cpu_list avr_cpu_list
> +#define cpu_signal_handler cpu_avr_signal_handler
> +#define cpu_mmu_index avr_cpu_mmu_index
> +
> +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
> +{
> +    return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
> +}
> +
> +void avr_cpu_tcg_init(void);
> +
> +void avr_cpu_list(void);
> +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 size,
> +                                int rw, int mmu_idx);
> +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
> +                                int len, bool is_write);
> +
> +enum {
> +    TB_FLAGS_FULL_ACCESS = 1,
> +    TB_FLAGS_SKIP = 2,
> +};
> +
> +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong
> *pc,
> +                                target_ulong *cs_base, uint32_t *pflags)
> +{
> +    uint32_t flags = 0;
> +
> +    *pc = env->pc_w * 2;
> +    *cs_base = 0;
> +
> +    if (env->fullacc) {
> +        flags |= TB_FLAGS_FULL_ACCESS;
> +    }
> +    if (env->skip) {
> +        flags |= TB_FLAGS_SKIP;
> +    }
> +
> +    *pflags = flags;
> +}
> +
> +static inline int cpu_interrupts_enabled(CPUAVRState *env)
> +{
> +    return env->sregI != 0;
> +}
> +
> +static inline uint8_t cpu_get_sreg(CPUAVRState *env)
> +{
> +    uint8_t sreg;
> +    sreg = (env->sregC) << 0
> +         | (env->sregZ) << 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;
> +    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;
> +}
> +
> +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> +                        MMUAccessType access_type, int mmu_idx,
> +                        bool probe, uintptr_t retaddr);
> +
> +typedef CPUAVRState CPUArchState;
> +typedef AVRCPU ArchCPU;
> +
> +#include "exec/cpu-all.h"
> +
> +#endif /* !defined (QEMU_AVR_CPU_H) */
> diff --git a/target/avr/cpu.c b/target/avr/cpu.c
> new file mode 100644
> index 0000000000..dae56d7845
> --- /dev/null
> +++ b/target/avr/cpu.c
> @@ -0,0 +1,576 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "qemu/qemu-print.h"
> +#include "exec/exec-all.h"
> +#include "cpu.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 *cs)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
> +    CPUAVRState *env = &cpu->env;
> +
> +    mcc->parent_reset(cs);
> +
> +    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;
> +
> +    env->skip = 0;
> +
> +    memset(env->r, 0, sizeof(env->r));
> +
> +    tlb_flush(cs);
> +}
> +
> +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);
> +    Error *local_err = NULL;
> +
> +    cpu_exec_realizefn(cs, &local_err);
> +    if (local_err != NULL) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    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)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +
> +    cpu_set_cpustate_pointers(cpu);
> +
> +#ifndef CONFIG_USER_ONLY
> +    /* Set the number of interrupts supported by the CPU. */
> +    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57);
> +#endif
> +}
> +
> +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
> +{
> +    ObjectClass *oc;
> +
> +    oc = object_class_by_name(cpu_model);
> +    if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL ||
> +        object_class_is_abstract(oc)) {
> +        oc = NULL;
> +    }
> +    return oc;
> +}
> +
> +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +    int i;
> +
> +    qemu_fprintf(f, "\n");
> +    qemu_fprintf(f, "PC:    %06x\n", env->pc_w);
> +    qemu_fprintf(f, "SP:      %04x\n", env->sp);
> +    qemu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
> +    qemu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
> +    qemu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
> +    qemu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
> +    qemu_fprintf(f, "EIND:      %02x\n", env->eind >> 16);
> +    qemu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
> +    qemu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
> +    qemu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
> +    qemu_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' : '-');
> +    qemu_fprintf(f, "SKIP:    %02x\n", env->skip);
> +
> +    qemu_fprintf(f, "\n");
> +    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
> +        qemu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
> +
> +        if ((i % 8) == 7) {
> +            qemu_fprintf(f, "\n");
> +        }
> +    }
> +    qemu_fprintf(f, "\n");
> +}
> +
> +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->tlb_fill = avr_cpu_tlb_fill;
> +    cc->tcg_initialize = avr_cpu_tcg_init;
> +    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;
> +    cc->gdb_core_xml_file = "avr-cpu.xml";
> +}
> +
> +static void avr_avr1_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +}
> +
> +static void avr_avr2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +}
> +
> +static void avr_avr25_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr3_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr31_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr35_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr51_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_xmega2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega7_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +typedef struct AVRCPUInfo {
> +    const char *name;
> +    void (*initfn)(Object *obj);
> +} AVRCPUInfo;
> +
> +
> +static void avr_cpu_list_entry(gpointer data, gpointer user_data)
> +{
> +    const char *typename = object_class_get_name(OBJECT_CLASS(data));
> +
> +    qemu_printf("%s\n", typename);
> +}
> +
> +void avr_cpu_list(void)
> +{
> +    GSList *list;
> +    list = object_class_get_list_sorted(TYPE_AVR_CPU, false);
> +    g_slist_foreach(list, avr_cpu_list_entry, NULL);
> +    g_slist_free(list);
> +}
> +
> +#define DEFINE_AVR_CPU_TYPE(model, initfn) \
> +    { \
> +        .parent = TYPE_AVR_CPU, \
> +        .instance_init = initfn, \
> +        .name = model "-avr-cpu", \
> +    }
> +
> +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,
> +    },
> +    DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn),
> +};
> +
> +DEFINE_TYPES(avr_cpu_type_info)
> diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
> new file mode 100644
> index 0000000000..20a5252482
> --- /dev/null
> +++ b/target/avr/gdbstub.c
> @@ -0,0 +1,85 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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;
> +
> +    /*  R */
> +    if (n < 32) {
> +        env->r[n] = *mem_buf;
> +        return 1;
> +    }
> +
> +    /*  SREG */
> +    if (n == 32) {
> +        cpu_set_sreg(env, *mem_buf);
> +        return 1;
> +    }
> +
> +    /*  SP */
> +    if (n == 33) {
> +        env->sp = lduw_p(mem_buf);
> +        return 2;
> +    }
> +
> +    /*  PC */
> +    if (n == 34) {
> +        env->pc_w = ldl_p(mem_buf) / 2;
> +        return 4;
> +    }
> +
> +    return 0;
> +}
> diff --git a/target/avr/machine.c b/target/avr/machine.c
> new file mode 100644
> index 0000000000..f6dcda7adc
> --- /dev/null
> +++ b/target/avr/machine.c
> @@ -0,0 +1,121 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "migration/cpu.h"
> +
> +static int get_sreg(QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg;
> +
> +    sreg = qemu_get_byte(f);
> +    cpu_set_sreg(env, sreg);
> +    return 0;
> +}
> +
> +static int put_sreg(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg = cpu_get_sreg(env);
> +
> +    qemu_put_byte(f, sreg);
> +    return 0;
> +}
> +
> +static const VMStateInfo vms_sreg = {
> +    .name = "sreg",
> +    .get = get_sreg,
> +    .put = put_sreg,
> +};
> +
> +static int get_segment(
> +    QEMUFile *f, void *opaque, size_t size, const VMStateField *field)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp;
> +
> +    temp = qemu_get_byte(f);
> +    *ramp = ((uint32_t)temp) << 16;
> +    return 0;
> +}
> +
> +static int put_segment(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp = *ramp >> 16;
> +
> +    qemu_put_byte(f, temp);
> +    return 0;
> +}
> +
> +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(env.skip, AVRCPU),
> +
> +        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS),
> +
> +        VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState),
> +        VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t),
> +        VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t),
> +        VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t),
> +        VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t),
> +        VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t),
> +
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml
> new file mode 100644
> index 0000000000..c4747f5b40
> --- /dev/null
> +++ b/gdb-xml/avr-cpu.xml
> @@ -0,0 +1,49 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
> +
> +     Copying and distribution of this file, with or without modification,
> +     are permitted in any medium without royalty provided the copyright
> +     notice and this notice are preserved.  -->
> +
> +<!-- Register numbers are hard-coded in order to maintain backward
> +     compatibility with older versions of tools that didn't use xml
> +     register descriptions.  -->
> +
> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
> +<feature name="org.gnu.gdb.riscv.cpu">
> +  <reg name="r0" bitsize="8" type="int" regnum="0"/>
> +  <reg name="r1" bitsize="8" type="int"/>
> +  <reg name="r2" bitsize="8" type="int"/>
> +  <reg name="r3" bitsize="8" type="int"/>
> +  <reg name="r4" bitsize="8" type="int"/>
> +  <reg name="r5" bitsize="8" type="int"/>
> +  <reg name="r6" bitsize="8" type="int"/>
> +  <reg name="r7" bitsize="8" type="int"/>
> +  <reg name="r8" bitsize="8" type="int"/>
> +  <reg name="r9" bitsize="8" type="int"/>
> +  <reg name="r10" bitsize="8" type="int"/>
> +  <reg name="r11" bitsize="8" type="int"/>
> +  <reg name="r12" bitsize="8" type="int"/>
> +  <reg name="r13" bitsize="8" type="int"/>
> +  <reg name="r14" bitsize="8" type="int"/>
> +  <reg name="r15" bitsize="8" type="int"/>
> +  <reg name="r16" bitsize="8" type="int"/>
> +  <reg name="r17" bitsize="8" type="int"/>
> +  <reg name="r18" bitsize="8" type="int"/>
> +  <reg name="r19" bitsize="8" type="int"/>
> +  <reg name="r20" bitsize="8" type="int"/>
> +  <reg name="r21" bitsize="8" type="int"/>
> +  <reg name="r22" bitsize="8" type="int"/>
> +  <reg name="r23" bitsize="8" type="int"/>
> +  <reg name="r24" bitsize="8" type="int"/>
> +  <reg name="r25" bitsize="8" type="int"/>
> +  <reg name="r26" bitsize="8" type="int"/>
> +  <reg name="r27" bitsize="8" type="int"/>
> +  <reg name="r28" bitsize="8" type="int"/>
> +  <reg name="r29" bitsize="8" type="int"/>
> +  <reg name="r30" bitsize="8" type="int"/>
> +  <reg name="r31" bitsize="8" type="int"/>
> +  <reg name="sreg" bitsize="8" type="int"/>
> +  <reg name="sp" bitsize="8" type="int"/>
> +  <reg name="pc" bitsize="8" type="int"/>
> +</feature>
> --
> 2.17.2 (Apple Git-113)
>
>
Aleksandar Markovic Nov. 24, 2019, 4:21 p.m. UTC | #2
On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com> wrote:

> This includes:
> - CPU data structures
> - object model classes and functions
> - migration functions
> - GDB hooks
>
> Co-developed-by: Michael Rolnik <mrolnik@gmail.com>
> Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Acked-by: Igor Mammedov <imammedo@redhat.com>
> ---


Unfortunately, it appears to me that support for AVR-specific gdb command
"info io_registers" is missing. This command looks very important in
overall AVR/gdb context, and I think we shouldn't leave it unsupported.
(please prove me wrong if I am mistaken here in any way).

Cc- ing Alex as he is the maintainer for gdbstub QEMU component, for his
opinion and advice.

Philippe, what happens in your experimental AVR setups, if the gdb command
 "info io_registers" is used?

Aleksandar

From gdb docs:

21.3.8 Atmel AVR

When configured for debugging the Atmel AVR, GDB supports the following
AVR-specific commands:
info io_registers

This command displays information about the AVR I/O registers. For each
register, GDB prints its number and value.




>  target/avr/cpu-param.h |  37 +++
>  target/avr/cpu-qom.h   |  54 ++++
>  target/avr/cpu.h       | 253 ++++++++++++++++++
>  target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
>  target/avr/gdbstub.c   |  85 ++++++
>  target/avr/machine.c   | 121 +++++++++
>  gdb-xml/avr-cpu.xml    |  49 ++++
>  7 files changed, 1175 insertions(+)
>  create mode 100644 target/avr/cpu-param.h
>  create mode 100644 target/avr/cpu-qom.h
>  create mode 100644 target/avr/cpu.h
>  create mode 100644 target/avr/cpu.c
>  create mode 100644 target/avr/gdbstub.c
>  create mode 100644 target/avr/machine.c
>  create mode 100644 gdb-xml/avr-cpu.xml
>
> diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
> new file mode 100644
> index 0000000000..ccd1ea3429
> --- /dev/null
> +++ b/target/avr/cpu-param.h
> @@ -0,0 +1,37 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_CPU_PARAM_H
> +#define AVR_CPU_PARAM_H 1
> +
> +#define TARGET_LONG_BITS 32
> +/*
> + * 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
> +
> +
> +#endif
> diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h
> new file mode 100644
> index 0000000000..e28b58c897
> --- /dev/null
> +++ b/target/avr/cpu-qom.h
> @@ -0,0 +1,54 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_QOM_H
> +#define QEMU_AVR_QOM_H
> +
> +#include "hw/core/cpu.h"
> +
> +#define TYPE_AVR_CPU "avr-cpu"
> +
> +#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 {
> +    /*< private >*/
> +    CPUClass parent_class;
> +    /*< public >*/
> +    DeviceRealize parent_realize;
> +    void (*parent_reset)(CPUState *cpu);
> +} AVRCPUClass;
> +
> +typedef struct AVRCPU AVRCPU;
> +
> +
> +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */
> diff --git a/target/avr/cpu.h b/target/avr/cpu.h
> new file mode 100644
> index 0000000000..ed9218af5f
> --- /dev/null
> +++ b/target/avr/cpu.h
> @@ -0,0 +1,253 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_H
> +#define QEMU_AVR_CPU_H
> +
> +#include "cpu-qom.h"
> +#include "exec/cpu-defs.h"
> +
> +#define TCG_GUEST_DEFAULT_MO 0
> +
> +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU
> +
> +/*
> + * AVR has two memory spaces, data & code.
> + * e.g. both have 0 address
> + * ST/LD instructions access data space
> + * LPM/SPM and instruction fetching access code memory space
> + */
> +#define MMU_CODE_IDX 0
> +#define MMU_DATA_IDX 1
> +
> +#define EXCP_RESET 1
> +#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
> +
> +/* Number of CPU registers */
> +#define NO_CPU_REGISTERS 32
> +/* Number of IO registers accessible by ld/st/in/out */
> +#define NO_IO_REGISTERS 64
> +
> +/*
> + * Offsets of AVR memory regions in host memory space.
> + *
> + * This is needed because the AVR has separate code and data address
> + * spaces that both have start from zero but have to go somewhere in
> + * host memory.
> + *
> + * It's also useful to know where some things are, like the IO registers.
> + */
> +/* Flash program memory */
> +#define OFFSET_CODE 0x00000000
> +/* CPU registers, IO registers, and SRAM */
> +#define OFFSET_DATA 0x00800000
> +/* CPU registers specifically, these are mapped at the start of data */
> +#define OFFSET_CPU_REGISTERS OFFSET_DATA
> +/*
> + * IO registers, including status register, stack pointer, and memory
> + * mapped peripherals, mapped just after CPU registers
> + */
> +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS)
> +
> +enum avr_features {
> +    AVR_FEATURE_SRAM,
> +
> +    AVR_FEATURE_1_BYTE_PC,
> +    AVR_FEATURE_2_BYTE_PC,
> +    AVR_FEATURE_3_BYTE_PC,
> +
> +    AVR_FEATURE_1_BYTE_SP,
> +    AVR_FEATURE_2_BYTE_SP,
> +
> +    AVR_FEATURE_BREAK,
> +    AVR_FEATURE_DES,
> +    AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
> +
> +    AVR_FEATURE_EIJMP_EICALL,
> +    AVR_FEATURE_IJMP_ICALL,
> +    AVR_FEATURE_JMP_CALL,
> +
> +    AVR_FEATURE_ADIW_SBIW,
> +
> +    AVR_FEATURE_SPM,
> +    AVR_FEATURE_SPMX,
> +
> +    AVR_FEATURE_ELPMX,
> +    AVR_FEATURE_ELPM,
> +    AVR_FEATURE_LPMX,
> +    AVR_FEATURE_LPM,
> +
> +    AVR_FEATURE_MOVW,
> +    AVR_FEATURE_MUL,
> +    AVR_FEATURE_RAMPD,
> +    AVR_FEATURE_RAMPX,
> +    AVR_FEATURE_RAMPY,
> +    AVR_FEATURE_RAMPZ,
> +};
> +
> +typedef struct CPUAVRState CPUAVRState;
> +
> +struct CPUAVRState {
> +    uint32_t pc_w; /* 0x003fffff up to 22 bits */
> +
> +    uint32_t sregC; /* 0x00000001 1 bit */
> +    uint32_t sregZ; /* 0x00000001 1 bit */
> +    uint32_t sregN; /* 0x00000001 1 bit */
> +    uint32_t sregV; /* 0x00000001 1 bit */
> +    uint32_t sregS; /* 0x00000001 1 bit */
> +    uint32_t sregH; /* 0x00000001 1 bit */
> +    uint32_t sregT; /* 0x00000001 1 bit */
> +    uint32_t sregI; /* 0x00000001 1 bit */
> +
> +    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 r[NO_CPU_REGISTERS]; /* 8 bits each */
> +    uint32_t sp; /* 16 bits */
> +
> +    uint32_t skip; /* if set skip instruction */
> +
> +    uint64_t intsrc; /* interrupt sources */
> +    bool fullacc; /* CPU/MEM if true MEM only otherwise */
> +
> +    uint32_t features;
> +};
> +
> +/**
> + *  AVRCPU:
> + *  @env: #CPUAVRState
> + *
> + *  A AVR CPU.
> + */
> +typedef struct AVRCPU {
> +    /*< private >*/
> +    CPUState parent_obj;
> +    /*< public >*/
> +
> +    CPUNegativeOffsetState neg;
> +    CPUAVRState env;
> +} AVRCPU;
> +
> +#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);
> +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);
> +
> +static inline int avr_feature(CPUAVRState *env, int feature)
> +{
> +    return (env->features & (1U << feature)) != 0;
> +}
> +
> +static inline void avr_set_feature(CPUAVRState *env, int feature)
> +{
> +    env->features |= (1U << feature);
> +}
> +
> +#define cpu_list avr_cpu_list
> +#define cpu_signal_handler cpu_avr_signal_handler
> +#define cpu_mmu_index avr_cpu_mmu_index
> +
> +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
> +{
> +    return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
> +}
> +
> +void avr_cpu_tcg_init(void);
> +
> +void avr_cpu_list(void);
> +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 size,
> +                                int rw, int mmu_idx);
> +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
> +                                int len, bool is_write);
> +
> +enum {
> +    TB_FLAGS_FULL_ACCESS = 1,
> +    TB_FLAGS_SKIP = 2,
> +};
> +
> +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong
> *pc,
> +                                target_ulong *cs_base, uint32_t *pflags)
> +{
> +    uint32_t flags = 0;
> +
> +    *pc = env->pc_w * 2;
> +    *cs_base = 0;
> +
> +    if (env->fullacc) {
> +        flags |= TB_FLAGS_FULL_ACCESS;
> +    }
> +    if (env->skip) {
> +        flags |= TB_FLAGS_SKIP;
> +    }
> +
> +    *pflags = flags;
> +}
> +
> +static inline int cpu_interrupts_enabled(CPUAVRState *env)
> +{
> +    return env->sregI != 0;
> +}
> +
> +static inline uint8_t cpu_get_sreg(CPUAVRState *env)
> +{
> +    uint8_t sreg;
> +    sreg = (env->sregC) << 0
> +         | (env->sregZ) << 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;
> +    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;
> +}
> +
> +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> +                        MMUAccessType access_type, int mmu_idx,
> +                        bool probe, uintptr_t retaddr);
> +
> +typedef CPUAVRState CPUArchState;
> +typedef AVRCPU ArchCPU;
> +
> +#include "exec/cpu-all.h"
> +
> +#endif /* !defined (QEMU_AVR_CPU_H) */
> diff --git a/target/avr/cpu.c b/target/avr/cpu.c
> new file mode 100644
> index 0000000000..dae56d7845
> --- /dev/null
> +++ b/target/avr/cpu.c
> @@ -0,0 +1,576 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "qemu/qemu-print.h"
> +#include "exec/exec-all.h"
> +#include "cpu.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 *cs)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
> +    CPUAVRState *env = &cpu->env;
> +
> +    mcc->parent_reset(cs);
> +
> +    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;
> +
> +    env->skip = 0;
> +
> +    memset(env->r, 0, sizeof(env->r));
> +
> +    tlb_flush(cs);
> +}
> +
> +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);
> +    Error *local_err = NULL;
> +
> +    cpu_exec_realizefn(cs, &local_err);
> +    if (local_err != NULL) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    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)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +
> +    cpu_set_cpustate_pointers(cpu);
> +
> +#ifndef CONFIG_USER_ONLY
> +    /* Set the number of interrupts supported by the CPU. */
> +    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57);
> +#endif
> +}
> +
> +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
> +{
> +    ObjectClass *oc;
> +
> +    oc = object_class_by_name(cpu_model);
> +    if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL ||
> +        object_class_is_abstract(oc)) {
> +        oc = NULL;
> +    }
> +    return oc;
> +}
> +
> +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +    int i;
> +
> +    qemu_fprintf(f, "\n");
> +    qemu_fprintf(f, "PC:    %06x\n", env->pc_w);
> +    qemu_fprintf(f, "SP:      %04x\n", env->sp);
> +    qemu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
> +    qemu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
> +    qemu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
> +    qemu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
> +    qemu_fprintf(f, "EIND:      %02x\n", env->eind >> 16);
> +    qemu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
> +    qemu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
> +    qemu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
> +    qemu_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' : '-');
> +    qemu_fprintf(f, "SKIP:    %02x\n", env->skip);
> +
> +    qemu_fprintf(f, "\n");
> +    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
> +        qemu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
> +
> +        if ((i % 8) == 7) {
> +            qemu_fprintf(f, "\n");
> +        }
> +    }
> +    qemu_fprintf(f, "\n");
> +}
> +
> +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->tlb_fill = avr_cpu_tlb_fill;
> +    cc->tcg_initialize = avr_cpu_tcg_init;
> +    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;
> +    cc->gdb_core_xml_file = "avr-cpu.xml";
> +}
> +
> +static void avr_avr1_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +}
> +
> +static void avr_avr2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +}
> +
> +static void avr_avr25_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr3_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr31_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr35_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr51_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_xmega2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega7_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +typedef struct AVRCPUInfo {
> +    const char *name;
> +    void (*initfn)(Object *obj);
> +} AVRCPUInfo;
> +
> +
> +static void avr_cpu_list_entry(gpointer data, gpointer user_data)
> +{
> +    const char *typename = object_class_get_name(OBJECT_CLASS(data));
> +
> +    qemu_printf("%s\n", typename);
> +}
> +
> +void avr_cpu_list(void)
> +{
> +    GSList *list;
> +    list = object_class_get_list_sorted(TYPE_AVR_CPU, false);
> +    g_slist_foreach(list, avr_cpu_list_entry, NULL);
> +    g_slist_free(list);
> +}
> +
> +#define DEFINE_AVR_CPU_TYPE(model, initfn) \
> +    { \
> +        .parent = TYPE_AVR_CPU, \
> +        .instance_init = initfn, \
> +        .name = model "-avr-cpu", \
> +    }
> +
> +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,
> +    },
> +    DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn),
> +};
> +
> +DEFINE_TYPES(avr_cpu_type_info)
> diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
> new file mode 100644
> index 0000000000..20a5252482
> --- /dev/null
> +++ b/target/avr/gdbstub.c
> @@ -0,0 +1,85 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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;
> +
> +    /*  R */
> +    if (n < 32) {
> +        env->r[n] = *mem_buf;
> +        return 1;
> +    }
> +
> +    /*  SREG */
> +    if (n == 32) {
> +        cpu_set_sreg(env, *mem_buf);
> +        return 1;
> +    }
> +
> +    /*  SP */
> +    if (n == 33) {
> +        env->sp = lduw_p(mem_buf);
> +        return 2;
> +    }
> +
> +    /*  PC */
> +    if (n == 34) {
> +        env->pc_w = ldl_p(mem_buf) / 2;
> +        return 4;
> +    }
> +
> +    return 0;
> +}
> diff --git a/target/avr/machine.c b/target/avr/machine.c
> new file mode 100644
> index 0000000000..f6dcda7adc
> --- /dev/null
> +++ b/target/avr/machine.c
> @@ -0,0 +1,121 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "migration/cpu.h"
> +
> +static int get_sreg(QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg;
> +
> +    sreg = qemu_get_byte(f);
> +    cpu_set_sreg(env, sreg);
> +    return 0;
> +}
> +
> +static int put_sreg(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg = cpu_get_sreg(env);
> +
> +    qemu_put_byte(f, sreg);
> +    return 0;
> +}
> +
> +static const VMStateInfo vms_sreg = {
> +    .name = "sreg",
> +    .get = get_sreg,
> +    .put = put_sreg,
> +};
> +
> +static int get_segment(
> +    QEMUFile *f, void *opaque, size_t size, const VMStateField *field)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp;
> +
> +    temp = qemu_get_byte(f);
> +    *ramp = ((uint32_t)temp) << 16;
> +    return 0;
> +}
> +
> +static int put_segment(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp = *ramp >> 16;
> +
> +    qemu_put_byte(f, temp);
> +    return 0;
> +}
> +
> +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(env.skip, AVRCPU),
> +
> +        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS),
> +
> +        VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState),
> +        VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t),
> +        VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t),
> +        VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t),
> +        VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t),
> +        VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t),
> +
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml
> new file mode 100644
> index 0000000000..c4747f5b40
> --- /dev/null
> +++ b/gdb-xml/avr-cpu.xml
> @@ -0,0 +1,49 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
> +
> +     Copying and distribution of this file, with or without modification,
> +     are permitted in any medium without royalty provided the copyright
> +     notice and this notice are preserved.  -->
> +
> +<!-- Register numbers are hard-coded in order to maintain backward
> +     compatibility with older versions of tools that didn't use xml
> +     register descriptions.  -->
> +
> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
> +<feature name="org.gnu.gdb.riscv.cpu">
> +  <reg name="r0" bitsize="8" type="int" regnum="0"/>
> +  <reg name="r1" bitsize="8" type="int"/>
> +  <reg name="r2" bitsize="8" type="int"/>
> +  <reg name="r3" bitsize="8" type="int"/>
> +  <reg name="r4" bitsize="8" type="int"/>
> +  <reg name="r5" bitsize="8" type="int"/>
> +  <reg name="r6" bitsize="8" type="int"/>
> +  <reg name="r7" bitsize="8" type="int"/>
> +  <reg name="r8" bitsize="8" type="int"/>
> +  <reg name="r9" bitsize="8" type="int"/>
> +  <reg name="r10" bitsize="8" type="int"/>
> +  <reg name="r11" bitsize="8" type="int"/>
> +  <reg name="r12" bitsize="8" type="int"/>
> +  <reg name="r13" bitsize="8" type="int"/>
> +  <reg name="r14" bitsize="8" type="int"/>
> +  <reg name="r15" bitsize="8" type="int"/>
> +  <reg name="r16" bitsize="8" type="int"/>
> +  <reg name="r17" bitsize="8" type="int"/>
> +  <reg name="r18" bitsize="8" type="int"/>
> +  <reg name="r19" bitsize="8" type="int"/>
> +  <reg name="r20" bitsize="8" type="int"/>
> +  <reg name="r21" bitsize="8" type="int"/>
> +  <reg name="r22" bitsize="8" type="int"/>
> +  <reg name="r23" bitsize="8" type="int"/>
> +  <reg name="r24" bitsize="8" type="int"/>
> +  <reg name="r25" bitsize="8" type="int"/>
> +  <reg name="r26" bitsize="8" type="int"/>
> +  <reg name="r27" bitsize="8" type="int"/>
> +  <reg name="r28" bitsize="8" type="int"/>
> +  <reg name="r29" bitsize="8" type="int"/>
> +  <reg name="r30" bitsize="8" type="int"/>
> +  <reg name="r31" bitsize="8" type="int"/>
> +  <reg name="sreg" bitsize="8" type="int"/>
> +  <reg name="sp" bitsize="8" type="int"/>
> +  <reg name="pc" bitsize="8" type="int"/>
> +</feature>
> --
> 2.17.2 (Apple Git-113)
>
>
Aleksandar Markovic Nov. 24, 2019, 8:08 p.m. UTC | #3
On Sunday, November 24, 2019, Aleksandar Markovic <
aleksandar.m.mail@gmail.com> wrote:

>
>
> On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com> wrote:
>
>> This includes:
>> - CPU data structures
>> - object model classes and functions
>> - migration functions
>> - GDB hooks
>>
>> Co-developed-by: Michael Rolnik <mrolnik@gmail.com>
>> Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk>
>> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
>> Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk>
>> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
>> Acked-by: Igor Mammedov <imammedo@redhat.com>
>> ---
>
>
> Unfortunately, it appears to me that support for AVR-specific gdb command
> "info io_registers" is missing.
>

Upon further investigation, I am not quite sure QEMU's AVR gdb stub is
wrong. (I thought there is a special command in gdb protocol for
AVR-specific "info io_registers", but that may not be true.)

In any case, here is the piece of gdb code that handles this command: (line
1551):

https://github.com/bminor/binutils-gdb/blob/502c64b9ac12cf2a35d3cb55c51e2eefd33a2494/gdb/avr-tdep.c

It wouldn't hurt if somebody tests that command on QEMU-emulated AVR
machine.

Yours,
Aleksandar




>
>
>
>
>
> This command looks very important in overall AVR/gdb context, and I think
> we shouldn't leave it unsupported. (please prove me wrong if I am mistaken
> here in any way).
>
> Cc- ing Alex as he is the maintainer for gdbstub QEMU component, for his
> opinion and advice.
>
> Philippe, what happens in your experimental AVR setups, if the gdb command
>  "info io_registers" is used?
>
> Aleksandar
>
> From gdb docs:
>
> 21.3.8 Atmel AVR
>
> When configured for debugging the Atmel AVR, GDB supports the following
> AVR-specific commands:
> info io_registers
>
> This command displays information about the AVR I/O registers. For each
> register, GDB prints its number and value.
>
>
>
>
>>  target/avr/cpu-param.h |  37 +++
>>  target/avr/cpu-qom.h   |  54 ++++
>>  target/avr/cpu.h       | 253 ++++++++++++++++++
>>  target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
>>  target/avr/gdbstub.c   |  85 ++++++
>>  target/avr/machine.c   | 121 +++++++++
>>  gdb-xml/avr-cpu.xml    |  49 ++++
>>  7 files changed, 1175 insertions(+)
>>  create mode 100644 target/avr/cpu-param.h
>>  create mode 100644 target/avr/cpu-qom.h
>>  create mode 100644 target/avr/cpu.h
>>  create mode 100644 target/avr/cpu.c
>>  create mode 100644 target/avr/gdbstub.c
>>  create mode 100644 target/avr/machine.c
>>  create mode 100644 gdb-xml/avr-cpu.xml
>>
>> diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
>> new file mode 100644
>> index 0000000000..ccd1ea3429
>> --- /dev/null
>> +++ b/target/avr/cpu-param.h
>> @@ -0,0 +1,37 @@
>> +/*
>> + * QEMU AVR CPU
>> + *
>> + * Copyright (c) 2019 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_CPU_PARAM_H
>> +#define AVR_CPU_PARAM_H 1
>> +
>> +#define TARGET_LONG_BITS 32
>> +/*
>> + * 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
>> +
>> +
>> +#endif
>> diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h
>> new file mode 100644
>> index 0000000000..e28b58c897
>> --- /dev/null
>> +++ b/target/avr/cpu-qom.h
>> @@ -0,0 +1,54 @@
>> +/*
>> + * QEMU AVR CPU
>> + *
>> + * Copyright (c) 2019 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_QOM_H
>> +#define QEMU_AVR_QOM_H
>> +
>> +#include "hw/core/cpu.h"
>> +
>> +#define TYPE_AVR_CPU "avr-cpu"
>> +
>> +#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 {
>> +    /*< private >*/
>> +    CPUClass parent_class;
>> +    /*< public >*/
>> +    DeviceRealize parent_realize;
>> +    void (*parent_reset)(CPUState *cpu);
>> +} AVRCPUClass;
>> +
>> +typedef struct AVRCPU AVRCPU;
>> +
>> +
>> +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */
>> diff --git a/target/avr/cpu.h b/target/avr/cpu.h
>> new file mode 100644
>> index 0000000000..ed9218af5f
>> --- /dev/null
>> +++ b/target/avr/cpu.h
>> @@ -0,0 +1,253 @@
>> +/*
>> + * QEMU AVR CPU
>> + *
>> + * Copyright (c) 2019 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_H
>> +#define QEMU_AVR_CPU_H
>> +
>> +#include "cpu-qom.h"
>> +#include "exec/cpu-defs.h"
>> +
>> +#define TCG_GUEST_DEFAULT_MO 0
>> +
>> +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU
>> +
>> +/*
>> + * AVR has two memory spaces, data & code.
>> + * e.g. both have 0 address
>> + * ST/LD instructions access data space
>> + * LPM/SPM and instruction fetching access code memory space
>> + */
>> +#define MMU_CODE_IDX 0
>> +#define MMU_DATA_IDX 1
>> +
>> +#define EXCP_RESET 1
>> +#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
>> +
>> +/* Number of CPU registers */
>> +#define NO_CPU_REGISTERS 32
>> +/* Number of IO registers accessible by ld/st/in/out */
>> +#define NO_IO_REGISTERS 64
>> +
>> +/*
>> + * Offsets of AVR memory regions in host memory space.
>> + *
>> + * This is needed because the AVR has separate code and data address
>> + * spaces that both have start from zero but have to go somewhere in
>> + * host memory.
>> + *
>> + * It's also useful to know where some things are, like the IO registers.
>> + */
>> +/* Flash program memory */
>> +#define OFFSET_CODE 0x00000000
>> +/* CPU registers, IO registers, and SRAM */
>> +#define OFFSET_DATA 0x00800000
>> +/* CPU registers specifically, these are mapped at the start of data */
>> +#define OFFSET_CPU_REGISTERS OFFSET_DATA
>> +/*
>> + * IO registers, including status register, stack pointer, and memory
>> + * mapped peripherals, mapped just after CPU registers
>> + */
>> +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS)
>> +
>> +enum avr_features {
>> +    AVR_FEATURE_SRAM,
>> +
>> +    AVR_FEATURE_1_BYTE_PC,
>> +    AVR_FEATURE_2_BYTE_PC,
>> +    AVR_FEATURE_3_BYTE_PC,
>> +
>> +    AVR_FEATURE_1_BYTE_SP,
>> +    AVR_FEATURE_2_BYTE_SP,
>> +
>> +    AVR_FEATURE_BREAK,
>> +    AVR_FEATURE_DES,
>> +    AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
>> +
>> +    AVR_FEATURE_EIJMP_EICALL,
>> +    AVR_FEATURE_IJMP_ICALL,
>> +    AVR_FEATURE_JMP_CALL,
>> +
>> +    AVR_FEATURE_ADIW_SBIW,
>> +
>> +    AVR_FEATURE_SPM,
>> +    AVR_FEATURE_SPMX,
>> +
>> +    AVR_FEATURE_ELPMX,
>> +    AVR_FEATURE_ELPM,
>> +    AVR_FEATURE_LPMX,
>> +    AVR_FEATURE_LPM,
>> +
>> +    AVR_FEATURE_MOVW,
>> +    AVR_FEATURE_MUL,
>> +    AVR_FEATURE_RAMPD,
>> +    AVR_FEATURE_RAMPX,
>> +    AVR_FEATURE_RAMPY,
>> +    AVR_FEATURE_RAMPZ,
>> +};
>> +
>> +typedef struct CPUAVRState CPUAVRState;
>> +
>> +struct CPUAVRState {
>> +    uint32_t pc_w; /* 0x003fffff up to 22 bits */
>> +
>> +    uint32_t sregC; /* 0x00000001 1 bit */
>> +    uint32_t sregZ; /* 0x00000001 1 bit */
>> +    uint32_t sregN; /* 0x00000001 1 bit */
>> +    uint32_t sregV; /* 0x00000001 1 bit */
>> +    uint32_t sregS; /* 0x00000001 1 bit */
>> +    uint32_t sregH; /* 0x00000001 1 bit */
>> +    uint32_t sregT; /* 0x00000001 1 bit */
>> +    uint32_t sregI; /* 0x00000001 1 bit */
>> +
>> +    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 r[NO_CPU_REGISTERS]; /* 8 bits each */
>> +    uint32_t sp; /* 16 bits */
>> +
>> +    uint32_t skip; /* if set skip instruction */
>> +
>> +    uint64_t intsrc; /* interrupt sources */
>> +    bool fullacc; /* CPU/MEM if true MEM only otherwise */
>> +
>> +    uint32_t features;
>> +};
>> +
>> +/**
>> + *  AVRCPU:
>> + *  @env: #CPUAVRState
>> + *
>> + *  A AVR CPU.
>> + */
>> +typedef struct AVRCPU {
>> +    /*< private >*/
>> +    CPUState parent_obj;
>> +    /*< public >*/
>> +
>> +    CPUNegativeOffsetState neg;
>> +    CPUAVRState env;
>> +} AVRCPU;
>> +
>> +#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);
>> +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);
>> +
>> +static inline int avr_feature(CPUAVRState *env, int feature)
>> +{
>> +    return (env->features & (1U << feature)) != 0;
>> +}
>> +
>> +static inline void avr_set_feature(CPUAVRState *env, int feature)
>> +{
>> +    env->features |= (1U << feature);
>> +}
>> +
>> +#define cpu_list avr_cpu_list
>> +#define cpu_signal_handler cpu_avr_signal_handler
>> +#define cpu_mmu_index avr_cpu_mmu_index
>> +
>> +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
>> +{
>> +    return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
>> +}
>> +
>> +void avr_cpu_tcg_init(void);
>> +
>> +void avr_cpu_list(void);
>> +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 size,
>> +                                int rw, int mmu_idx);
>> +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
>> +                                int len, bool is_write);
>> +
>> +enum {
>> +    TB_FLAGS_FULL_ACCESS = 1,
>> +    TB_FLAGS_SKIP = 2,
>> +};
>> +
>> +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong
>> *pc,
>> +                                target_ulong *cs_base, uint32_t *pflags)
>> +{
>> +    uint32_t flags = 0;
>> +
>> +    *pc = env->pc_w * 2;
>> +    *cs_base = 0;
>> +
>> +    if (env->fullacc) {
>> +        flags |= TB_FLAGS_FULL_ACCESS;
>> +    }
>> +    if (env->skip) {
>> +        flags |= TB_FLAGS_SKIP;
>> +    }
>> +
>> +    *pflags = flags;
>> +}
>> +
>> +static inline int cpu_interrupts_enabled(CPUAVRState *env)
>> +{
>> +    return env->sregI != 0;
>> +}
>> +
>> +static inline uint8_t cpu_get_sreg(CPUAVRState *env)
>> +{
>> +    uint8_t sreg;
>> +    sreg = (env->sregC) << 0
>> +         | (env->sregZ) << 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;
>> +    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;
>> +}
>> +
>> +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>> +                        MMUAccessType access_type, int mmu_idx,
>> +                        bool probe, uintptr_t retaddr);
>> +
>> +typedef CPUAVRState CPUArchState;
>> +typedef AVRCPU ArchCPU;
>> +
>> +#include "exec/cpu-all.h"
>> +
>> +#endif /* !defined (QEMU_AVR_CPU_H) */
>> diff --git a/target/avr/cpu.c b/target/avr/cpu.c
>> new file mode 100644
>> index 0000000000..dae56d7845
>> --- /dev/null
>> +++ b/target/avr/cpu.c
>> @@ -0,0 +1,576 @@
>> +/*
>> + * QEMU AVR CPU
>> + *
>> + * Copyright (c) 2019 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 "qemu/qemu-print.h"
>> +#include "exec/exec-all.h"
>> +#include "cpu.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 *cs)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(cs);
>> +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    mcc->parent_reset(cs);
>> +
>> +    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;
>> +
>> +    env->skip = 0;
>> +
>> +    memset(env->r, 0, sizeof(env->r));
>> +
>> +    tlb_flush(cs);
>> +}
>> +
>> +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);
>> +    Error *local_err = NULL;
>> +
>> +    cpu_exec_realizefn(cs, &local_err);
>> +    if (local_err != NULL) {
>> +        error_propagate(errp, local_err);
>> +        return;
>> +    }
>> +    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)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +
>> +    cpu_set_cpustate_pointers(cpu);
>> +
>> +#ifndef CONFIG_USER_ONLY
>> +    /* Set the number of interrupts supported by the CPU. */
>> +    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57);
>> +#endif
>> +}
>> +
>> +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
>> +{
>> +    ObjectClass *oc;
>> +
>> +    oc = object_class_by_name(cpu_model);
>> +    if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL ||
>> +        object_class_is_abstract(oc)) {
>> +        oc = NULL;
>> +    }
>> +    return oc;
>> +}
>> +
>> +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(cs);
>> +    CPUAVRState *env = &cpu->env;
>> +    int i;
>> +
>> +    qemu_fprintf(f, "\n");
>> +    qemu_fprintf(f, "PC:    %06x\n", env->pc_w);
>> +    qemu_fprintf(f, "SP:      %04x\n", env->sp);
>> +    qemu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
>> +    qemu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
>> +    qemu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
>> +    qemu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
>> +    qemu_fprintf(f, "EIND:      %02x\n", env->eind >> 16);
>> +    qemu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
>> +    qemu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
>> +    qemu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
>> +    qemu_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' : '-');
>> +    qemu_fprintf(f, "SKIP:    %02x\n", env->skip);
>> +
>> +    qemu_fprintf(f, "\n");
>> +    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
>> +        qemu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
>> +
>> +        if ((i % 8) == 7) {
>> +            qemu_fprintf(f, "\n");
>> +        }
>> +    }
>> +    qemu_fprintf(f, "\n");
>> +}
>> +
>> +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->tlb_fill = avr_cpu_tlb_fill;
>> +    cc->tcg_initialize = avr_cpu_tcg_init;
>> +    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;
>> +    cc->gdb_core_xml_file = "avr-cpu.xml";
>> +}
>> +
>> +static void avr_avr1_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +}
>> +
>> +static void avr_avr2_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +}
>> +
>> +static void avr_avr25_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +}
>> +
>> +static void avr_avr3_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +}
>> +
>> +static void avr_avr31_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>> +    avr_set_feature(env, AVR_FEATURE_ELPM);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +}
>> +
>> +static void avr_avr35_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +}
>> +
>> +static void avr_avr4_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +}
>> +
>> +static void avr_avr5_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +}
>> +
>> +static void avr_avr51_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>> +    avr_set_feature(env, AVR_FEATURE_ELPM);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +}
>> +
>> +static void avr_avr6_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>> +    avr_set_feature(env, AVR_FEATURE_ELPM);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +}
>> +
>> +static void avr_xmega2_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +    avr_set_feature(env, AVR_FEATURE_RMW);
>> +}
>> +
>> +static void avr_xmega4_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>> +    avr_set_feature(env, AVR_FEATURE_ELPM);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +    avr_set_feature(env, AVR_FEATURE_RMW);
>> +}
>> +
>> +static void avr_xmega5_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>> +    avr_set_feature(env, AVR_FEATURE_ELPM);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +    avr_set_feature(env, AVR_FEATURE_RMW);
>> +}
>> +
>> +static void avr_xmega6_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>> +    avr_set_feature(env, AVR_FEATURE_ELPM);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +    avr_set_feature(env, AVR_FEATURE_RMW);
>> +}
>> +
>> +static void avr_xmega7_initfn(Object *obj)
>> +{
>> +    AVRCPU *cpu = AVR_CPU(obj);
>> +    CPUAVRState *env = &cpu->env;
>> +
>> +    avr_set_feature(env, AVR_FEATURE_LPM);
>> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>> +    avr_set_feature(env, AVR_FEATURE_SRAM);
>> +    avr_set_feature(env, AVR_FEATURE_BREAK);
>> +
>> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
>> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
>> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
>> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>> +    avr_set_feature(env, AVR_FEATURE_ELPM);
>> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>> +    avr_set_feature(env, AVR_FEATURE_LPMX);
>> +    avr_set_feature(env, AVR_FEATURE_MOVW);
>> +    avr_set_feature(env, AVR_FEATURE_MUL);
>> +    avr_set_feature(env, AVR_FEATURE_RMW);
>> +}
>> +
>> +typedef struct AVRCPUInfo {
>> +    const char *name;
>> +    void (*initfn)(Object *obj);
>> +} AVRCPUInfo;
>> +
>> +
>> +static void avr_cpu_list_entry(gpointer data, gpointer user_data)
>> +{
>> +    const char *typename = object_class_get_name(OBJECT_CLASS(data));
>> +
>> +    qemu_printf("%s\n", typename);
>> +}
>> +
>> +void avr_cpu_list(void)
>> +{
>> +    GSList *list;
>> +    list = object_class_get_list_sorted(TYPE_AVR_CPU, false);
>> +    g_slist_foreach(list, avr_cpu_list_entry, NULL);
>> +    g_slist_free(list);
>> +}
>> +
>> +#define DEFINE_AVR_CPU_TYPE(model, initfn) \
>> +    { \
>> +        .parent = TYPE_AVR_CPU, \
>> +        .instance_init = initfn, \
>> +        .name = model "-avr-cpu", \
>> +    }
>> +
>> +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,
>> +    },
>> +    DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn),
>> +    DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn),
>> +    DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn),
>> +    DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn),
>> +    DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn),
>> +    DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn),
>> +    DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn),
>> +};
>> +
>> +DEFINE_TYPES(avr_cpu_type_info)
>> diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
>> new file mode 100644
>> index 0000000000..20a5252482
>> --- /dev/null
>> +++ b/target/avr/gdbstub.c
>> @@ -0,0 +1,85 @@
>> +/*
>> + * QEMU AVR CPU
>> + *
>> + * Copyright (c) 2019 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;
>> +
>> +    /*  R */
>> +    if (n < 32) {
>> +        env->r[n] = *mem_buf;
>> +        return 1;
>> +    }
>> +
>> +    /*  SREG */
>> +    if (n == 32) {
>> +        cpu_set_sreg(env, *mem_buf);
>> +        return 1;
>> +    }
>> +
>> +    /*  SP */
>> +    if (n == 33) {
>> +        env->sp = lduw_p(mem_buf);
>> +        return 2;
>> +    }
>> +
>> +    /*  PC */
>> +    if (n == 34) {
>> +        env->pc_w = ldl_p(mem_buf) / 2;
>> +        return 4;
>> +    }
>> +
>> +    return 0;
>> +}
>> diff --git a/target/avr/machine.c b/target/avr/machine.c
>> new file mode 100644
>> index 0000000000..f6dcda7adc
>> --- /dev/null
>> +++ b/target/avr/machine.c
>> @@ -0,0 +1,121 @@
>> +/*
>> + * QEMU AVR CPU
>> + *
>> + * Copyright (c) 2019 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 "migration/cpu.h"
>> +
>> +static int get_sreg(QEMUFile *f, void *opaque, size_t size,
>> +    const VMStateField *field)
>> +{
>> +    CPUAVRState *env = opaque;
>> +    uint8_t sreg;
>> +
>> +    sreg = qemu_get_byte(f);
>> +    cpu_set_sreg(env, sreg);
>> +    return 0;
>> +}
>> +
>> +static int put_sreg(
>> +    QEMUFile *f, void *opaque, size_t size,
>> +    const VMStateField *field, QJSON *vmdesc)
>> +{
>> +    CPUAVRState *env = opaque;
>> +    uint8_t sreg = cpu_get_sreg(env);
>> +
>> +    qemu_put_byte(f, sreg);
>> +    return 0;
>> +}
>> +
>> +static const VMStateInfo vms_sreg = {
>> +    .name = "sreg",
>> +    .get = get_sreg,
>> +    .put = put_sreg,
>> +};
>> +
>> +static int get_segment(
>> +    QEMUFile *f, void *opaque, size_t size, const VMStateField *field)
>> +{
>> +    uint32_t *ramp = opaque;
>> +    uint8_t temp;
>> +
>> +    temp = qemu_get_byte(f);
>> +    *ramp = ((uint32_t)temp) << 16;
>> +    return 0;
>> +}
>> +
>> +static int put_segment(
>> +    QEMUFile *f, void *opaque, size_t size,
>> +    const VMStateField *field, QJSON *vmdesc)
>> +{
>> +    uint32_t *ramp = opaque;
>> +    uint8_t temp = *ramp >> 16;
>> +
>> +    qemu_put_byte(f, temp);
>> +    return 0;
>> +}
>> +
>> +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(env.skip, AVRCPU),
>> +
>> +        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS),
>> +
>> +        VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState),
>> +        VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t),
>> +        VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t),
>> +        VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t),
>> +        VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t),
>> +        VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t),
>> +
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml
>> new file mode 100644
>> index 0000000000..c4747f5b40
>> --- /dev/null
>> +++ b/gdb-xml/avr-cpu.xml
>> @@ -0,0 +1,49 @@
>> +<?xml version="1.0"?>
>> +<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
>> +
>> +     Copying and distribution of this file, with or without modification,
>> +     are permitted in any medium without royalty provided the copyright
>> +     notice and this notice are preserved.  -->
>> +
>> +<!-- Register numbers are hard-coded in order to maintain backward
>> +     compatibility with older versions of tools that didn't use xml
>> +     register descriptions.  -->
>> +
>> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
>> +<feature name="org.gnu.gdb.riscv.cpu">
>> +  <reg name="r0" bitsize="8" type="int" regnum="0"/>
>> +  <reg name="r1" bitsize="8" type="int"/>
>> +  <reg name="r2" bitsize="8" type="int"/>
>> +  <reg name="r3" bitsize="8" type="int"/>
>> +  <reg name="r4" bitsize="8" type="int"/>
>> +  <reg name="r5" bitsize="8" type="int"/>
>> +  <reg name="r6" bitsize="8" type="int"/>
>> +  <reg name="r7" bitsize="8" type="int"/>
>> +  <reg name="r8" bitsize="8" type="int"/>
>> +  <reg name="r9" bitsize="8" type="int"/>
>> +  <reg name="r10" bitsize="8" type="int"/>
>> +  <reg name="r11" bitsize="8" type="int"/>
>> +  <reg name="r12" bitsize="8" type="int"/>
>> +  <reg name="r13" bitsize="8" type="int"/>
>> +  <reg name="r14" bitsize="8" type="int"/>
>> +  <reg name="r15" bitsize="8" type="int"/>
>> +  <reg name="r16" bitsize="8" type="int"/>
>> +  <reg name="r17" bitsize="8" type="int"/>
>> +  <reg name="r18" bitsize="8" type="int"/>
>> +  <reg name="r19" bitsize="8" type="int"/>
>> +  <reg name="r20" bitsize="8" type="int"/>
>> +  <reg name="r21" bitsize="8" type="int"/>
>> +  <reg name="r22" bitsize="8" type="int"/>
>> +  <reg name="r23" bitsize="8" type="int"/>
>> +  <reg name="r24" bitsize="8" type="int"/>
>> +  <reg name="r25" bitsize="8" type="int"/>
>> +  <reg name="r26" bitsize="8" type="int"/>
>> +  <reg name="r27" bitsize="8" type="int"/>
>> +  <reg name="r28" bitsize="8" type="int"/>
>> +  <reg name="r29" bitsize="8" type="int"/>
>> +  <reg name="r30" bitsize="8" type="int"/>
>> +  <reg name="r31" bitsize="8" type="int"/>
>> +  <reg name="sreg" bitsize="8" type="int"/>
>> +  <reg name="sp" bitsize="8" type="int"/>
>> +  <reg name="pc" bitsize="8" type="int"/>
>> +</feature>
>> --
>> 2.17.2 (Apple Git-113)
>>
>>
Aleksandar Markovic Nov. 25, 2019, 1:29 a.m. UTC | #4
On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com> wrote:

> This includes:
> - CPU data structures
> - object model classes and functions
> - migration functions
> - GDB hooks
>
> Co-developed-by: Michael Rolnik <mrolnik@gmail.com>
> Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Acked-by: Igor Mammedov <imammedo@redhat.com>
> ---
>  target/avr/cpu-param.h |  37 +++
>  target/avr/cpu-qom.h   |  54 ++++
>  target/avr/cpu.h       | 253 ++++++++++++++++++
>  target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
>  target/avr/gdbstub.c   |  85 ++++++
>  target/avr/machine.c   | 121 +++++++++
>  gdb-xml/avr-cpu.xml    |  49 ++++
>  7 files changed, 1175 insertions(+)


Very good!! Thanks a lot!! I see you ran the script git.orderfile, and now
headers appear before c files! Even in thsi changed file summary. In v35,
it used to be:

 gdb-xml/avr-cpu.xml    |  49 ++++
 target/avr/cpu-param.h |  37 +++
 target/avr/cpu-qom.h   |  54 ++++
 target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
 target/avr/cpu.h       | 253 ++++++++++++++++++
 target/avr/gdbstub.c   |  85 ++++++
 target/avr/machine.c   | 121 +++++++++
 7 files changed, 1175 insertions(+)


>  create mode 100644 target/avr/cpu-param.h
>  create mode 100644 target/avr/cpu-qom.h
>  create mode 100644 target/avr/cpu.h
>  create mode 100644 target/avr/cpu.c
>  create mode 100644 target/avr/gdbstub.c
>  create mode 100644 target/avr/machine.c
>  create mode 100644 gdb-xml/avr-cpu.xml
>
> diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
> new file mode 100644
> index 0000000000..ccd1ea3429
> --- /dev/null
> +++ b/target/avr/cpu-param.h
> @@ -0,0 +1,37 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_CPU_PARAM_H
> +#define AVR_CPU_PARAM_H 1
> +
> +#define TARGET_LONG_BITS 32
> +/*
> + * 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
> +
> +
> +#endif
> diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h
> new file mode 100644
> index 0000000000..e28b58c897
> --- /dev/null
> +++ b/target/avr/cpu-qom.h
> @@ -0,0 +1,54 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_QOM_H
> +#define QEMU_AVR_QOM_H
> +
> +#include "hw/core/cpu.h"
> +
> +#define TYPE_AVR_CPU "avr-cpu"
> +
> +#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 {
> +    /*< private >*/
> +    CPUClass parent_class;
> +    /*< public >*/
> +    DeviceRealize parent_realize;
> +    void (*parent_reset)(CPUState *cpu);
> +} AVRCPUClass;
> +
> +typedef struct AVRCPU AVRCPU;
> +
> +
> +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */
> diff --git a/target/avr/cpu.h b/target/avr/cpu.h
> new file mode 100644
> index 0000000000..ed9218af5f
> --- /dev/null
> +++ b/target/avr/cpu.h
> @@ -0,0 +1,253 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_H
> +#define QEMU_AVR_CPU_H
> +
> +#include "cpu-qom.h"
> +#include "exec/cpu-defs.h"
> +
> +#define TCG_GUEST_DEFAULT_MO 0
> +
> +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU
> +
> +/*
> + * AVR has two memory spaces, data & code.
> + * e.g. both have 0 address
> + * ST/LD instructions access data space
> + * LPM/SPM and instruction fetching access code memory space
> + */
> +#define MMU_CODE_IDX 0
> +#define MMU_DATA_IDX 1
> +
> +#define EXCP_RESET 1
> +#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
> +
> +/* Number of CPU registers */
> +#define NO_CPU_REGISTERS 32
> +/* Number of IO registers accessible by ld/st/in/out */
> +#define NO_IO_REGISTERS 64
> +
> +/*
> + * Offsets of AVR memory regions in host memory space.
> + *
> + * This is needed because the AVR has separate code and data address
> + * spaces that both have start from zero but have to go somewhere in
> + * host memory.
> + *
> + * It's also useful to know where some things are, like the IO registers.
> + */
> +/* Flash program memory */
> +#define OFFSET_CODE 0x00000000
> +/* CPU registers, IO registers, and SRAM */
> +#define OFFSET_DATA 0x00800000
> +/* CPU registers specifically, these are mapped at the start of data */
> +#define OFFSET_CPU_REGISTERS OFFSET_DATA
> +/*
> + * IO registers, including status register, stack pointer, and memory
> + * mapped peripherals, mapped just after CPU registers
> + */
> +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS)
> +
> +enum avr_features {
> +    AVR_FEATURE_SRAM,
> +
> +    AVR_FEATURE_1_BYTE_PC,
> +    AVR_FEATURE_2_BYTE_PC,
> +    AVR_FEATURE_3_BYTE_PC,
> +
> +    AVR_FEATURE_1_BYTE_SP,
> +    AVR_FEATURE_2_BYTE_SP,
> +
> +    AVR_FEATURE_BREAK,
> +    AVR_FEATURE_DES,
> +    AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
> +
> +    AVR_FEATURE_EIJMP_EICALL,
> +    AVR_FEATURE_IJMP_ICALL,
> +    AVR_FEATURE_JMP_CALL,
> +
> +    AVR_FEATURE_ADIW_SBIW,
> +
> +    AVR_FEATURE_SPM,
> +    AVR_FEATURE_SPMX,
> +
> +    AVR_FEATURE_ELPMX,
> +    AVR_FEATURE_ELPM,
> +    AVR_FEATURE_LPMX,
> +    AVR_FEATURE_LPM,
> +
> +    AVR_FEATURE_MOVW,
> +    AVR_FEATURE_MUL,
> +    AVR_FEATURE_RAMPD,
> +    AVR_FEATURE_RAMPX,
> +    AVR_FEATURE_RAMPY,
> +    AVR_FEATURE_RAMPZ,
> +};
> +
> +typedef struct CPUAVRState CPUAVRState;
> +
> +struct CPUAVRState {
> +    uint32_t pc_w; /* 0x003fffff up to 22 bits */
> +
> +    uint32_t sregC; /* 0x00000001 1 bit */
> +    uint32_t sregZ; /* 0x00000001 1 bit */
> +    uint32_t sregN; /* 0x00000001 1 bit */
> +    uint32_t sregV; /* 0x00000001 1 bit */
> +    uint32_t sregS; /* 0x00000001 1 bit */
> +    uint32_t sregH; /* 0x00000001 1 bit */
> +    uint32_t sregT; /* 0x00000001 1 bit */
> +    uint32_t sregI; /* 0x00000001 1 bit */
> +
> +    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 r[NO_CPU_REGISTERS]; /* 8 bits each */
> +    uint32_t sp; /* 16 bits */
> +
> +    uint32_t skip; /* if set skip instruction */
> +
> +    uint64_t intsrc; /* interrupt sources */
> +    bool fullacc; /* CPU/MEM if true MEM only otherwise */
> +
> +    uint32_t features;
> +};
> +
> +/**
> + *  AVRCPU:
> + *  @env: #CPUAVRState
> + *
> + *  A AVR CPU.
> + */
> +typedef struct AVRCPU {
> +    /*< private >*/
> +    CPUState parent_obj;
> +    /*< public >*/
> +
> +    CPUNegativeOffsetState neg;
> +    CPUAVRState env;
> +} AVRCPU;
> +
> +#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);
> +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);
> +
> +static inline int avr_feature(CPUAVRState *env, int feature)
> +{
> +    return (env->features & (1U << feature)) != 0;
> +}
> +
> +static inline void avr_set_feature(CPUAVRState *env, int feature)
> +{
> +    env->features |= (1U << feature);
> +}
> +
> +#define cpu_list avr_cpu_list
> +#define cpu_signal_handler cpu_avr_signal_handler
> +#define cpu_mmu_index avr_cpu_mmu_index
> +
> +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
> +{
> +    return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
> +}
> +
> +void avr_cpu_tcg_init(void);
> +
> +void avr_cpu_list(void);
> +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 size,
> +                                int rw, int mmu_idx);
> +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
> +                                int len, bool is_write);
> +
> +enum {
> +    TB_FLAGS_FULL_ACCESS = 1,
> +    TB_FLAGS_SKIP = 2,
> +};
> +
> +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong
> *pc,
> +                                target_ulong *cs_base, uint32_t *pflags)
> +{
> +    uint32_t flags = 0;
> +
> +    *pc = env->pc_w * 2;
> +    *cs_base = 0;
> +
> +    if (env->fullacc) {
> +        flags |= TB_FLAGS_FULL_ACCESS;
> +    }
> +    if (env->skip) {
> +        flags |= TB_FLAGS_SKIP;
> +    }
> +
> +    *pflags = flags;
> +}
> +
> +static inline int cpu_interrupts_enabled(CPUAVRState *env)
> +{
> +    return env->sregI != 0;
> +}
> +
> +static inline uint8_t cpu_get_sreg(CPUAVRState *env)
> +{
> +    uint8_t sreg;
> +    sreg = (env->sregC) << 0
> +         | (env->sregZ) << 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;
> +    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;
> +}
> +
> +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> +                        MMUAccessType access_type, int mmu_idx,
> +                        bool probe, uintptr_t retaddr);
> +
> +typedef CPUAVRState CPUArchState;
> +typedef AVRCPU ArchCPU;
> +
> +#include "exec/cpu-all.h"
> +
> +#endif /* !defined (QEMU_AVR_CPU_H) */
> diff --git a/target/avr/cpu.c b/target/avr/cpu.c
> new file mode 100644
> index 0000000000..dae56d7845
> --- /dev/null
> +++ b/target/avr/cpu.c
> @@ -0,0 +1,576 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "qemu/qemu-print.h"
> +#include "exec/exec-all.h"
> +#include "cpu.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 *cs)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
> +    CPUAVRState *env = &cpu->env;
> +
> +    mcc->parent_reset(cs);
> +
> +    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;
> +
> +    env->skip = 0;
> +
> +    memset(env->r, 0, sizeof(env->r));
> +
> +    tlb_flush(cs);
> +}
> +
> +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);
> +    Error *local_err = NULL;
> +
> +    cpu_exec_realizefn(cs, &local_err);
> +    if (local_err != NULL) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    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)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +
> +    cpu_set_cpustate_pointers(cpu);
> +
> +#ifndef CONFIG_USER_ONLY
> +    /* Set the number of interrupts supported by the CPU. */
> +    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57);
> +#endif
> +}
> +
> +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
> +{
> +    ObjectClass *oc;
> +
> +    oc = object_class_by_name(cpu_model);
> +    if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL ||
> +        object_class_is_abstract(oc)) {
> +        oc = NULL;
> +    }
> +    return oc;
> +}
> +
> +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +    int i;
> +
> +    qemu_fprintf(f, "\n");
> +    qemu_fprintf(f, "PC:    %06x\n", env->pc_w);
> +    qemu_fprintf(f, "SP:      %04x\n", env->sp);
> +    qemu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
> +    qemu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
> +    qemu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
> +    qemu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
> +    qemu_fprintf(f, "EIND:      %02x\n", env->eind >> 16);
> +    qemu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
> +    qemu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
> +    qemu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
> +    qemu_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' : '-');
> +    qemu_fprintf(f, "SKIP:    %02x\n", env->skip);
> +
> +    qemu_fprintf(f, "\n");
> +    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
> +        qemu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
> +
> +        if ((i % 8) == 7) {
> +            qemu_fprintf(f, "\n");
> +        }
> +    }
> +    qemu_fprintf(f, "\n");
> +}
> +
> +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->tlb_fill = avr_cpu_tlb_fill;
> +    cc->tcg_initialize = avr_cpu_tcg_init;
> +    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;
> +    cc->gdb_core_xml_file = "avr-cpu.xml";
> +}
> +
> +static void avr_avr1_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +}
> +
> +static void avr_avr2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +}
> +
> +static void avr_avr25_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr3_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr31_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr35_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr51_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_xmega2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega7_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +typedef struct AVRCPUInfo {
> +    const char *name;
> +    void (*initfn)(Object *obj);
> +} AVRCPUInfo;
> +
> +
> +static void avr_cpu_list_entry(gpointer data, gpointer user_data)
> +{
> +    const char *typename = object_class_get_name(OBJECT_CLASS(data));
> +
> +    qemu_printf("%s\n", typename);
> +}
> +
> +void avr_cpu_list(void)
> +{
> +    GSList *list;
> +    list = object_class_get_list_sorted(TYPE_AVR_CPU, false);
> +    g_slist_foreach(list, avr_cpu_list_entry, NULL);
> +    g_slist_free(list);
> +}
> +
> +#define DEFINE_AVR_CPU_TYPE(model, initfn) \
> +    { \
> +        .parent = TYPE_AVR_CPU, \
> +        .instance_init = initfn, \
> +        .name = model "-avr-cpu", \
> +    }
> +
> +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,
> +    },
> +    DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn),
> +};
> +
> +DEFINE_TYPES(avr_cpu_type_info)
> diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
> new file mode 100644
> index 0000000000..20a5252482
> --- /dev/null
> +++ b/target/avr/gdbstub.c
> @@ -0,0 +1,85 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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;
> +
> +    /*  R */
> +    if (n < 32) {
> +        env->r[n] = *mem_buf;
> +        return 1;
> +    }
> +
> +    /*  SREG */
> +    if (n == 32) {
> +        cpu_set_sreg(env, *mem_buf);
> +        return 1;
> +    }
> +
> +    /*  SP */
> +    if (n == 33) {
> +        env->sp = lduw_p(mem_buf);
> +        return 2;
> +    }
> +
> +    /*  PC */
> +    if (n == 34) {
> +        env->pc_w = ldl_p(mem_buf) / 2;
> +        return 4;
> +    }
> +
> +    return 0;
> +}
> diff --git a/target/avr/machine.c b/target/avr/machine.c
> new file mode 100644
> index 0000000000..f6dcda7adc
> --- /dev/null
> +++ b/target/avr/machine.c
> @@ -0,0 +1,121 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "migration/cpu.h"
> +
> +static int get_sreg(QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg;
> +
> +    sreg = qemu_get_byte(f);
> +    cpu_set_sreg(env, sreg);
> +    return 0;
> +}
> +
> +static int put_sreg(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg = cpu_get_sreg(env);
> +
> +    qemu_put_byte(f, sreg);
> +    return 0;
> +}
> +
> +static const VMStateInfo vms_sreg = {
> +    .name = "sreg",
> +    .get = get_sreg,
> +    .put = put_sreg,
> +};
> +
> +static int get_segment(
> +    QEMUFile *f, void *opaque, size_t size, const VMStateField *field)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp;
> +
> +    temp = qemu_get_byte(f);
> +    *ramp = ((uint32_t)temp) << 16;
> +    return 0;
> +}
> +
> +static int put_segment(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp = *ramp >> 16;
> +
> +    qemu_put_byte(f, temp);
> +    return 0;
> +}
> +
> +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(env.skip, AVRCPU),
> +
> +        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS),
> +
> +        VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState),
> +        VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t),
> +        VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t),
> +        VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t),
> +        VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t),
> +        VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t),
> +
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml
> new file mode 100644
> index 0000000000..c4747f5b40
> --- /dev/null
> +++ b/gdb-xml/avr-cpu.xml
> @@ -0,0 +1,49 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
> +
> +     Copying and distribution of this file, with or without modification,
> +     are permitted in any medium without royalty provided the copyright
> +     notice and this notice are preserved.  -->
> +
> +<!-- Register numbers are hard-coded in order to maintain backward
> +     compatibility with older versions of tools that didn't use xml
> +     register descriptions.  -->
> +
> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
> +<feature name="org.gnu.gdb.riscv.cpu">
> +  <reg name="r0" bitsize="8" type="int" regnum="0"/>
> +  <reg name="r1" bitsize="8" type="int"/>
> +  <reg name="r2" bitsize="8" type="int"/>
> +  <reg name="r3" bitsize="8" type="int"/>
> +  <reg name="r4" bitsize="8" type="int"/>
> +  <reg name="r5" bitsize="8" type="int"/>
> +  <reg name="r6" bitsize="8" type="int"/>
> +  <reg name="r7" bitsize="8" type="int"/>
> +  <reg name="r8" bitsize="8" type="int"/>
> +  <reg name="r9" bitsize="8" type="int"/>
> +  <reg name="r10" bitsize="8" type="int"/>
> +  <reg name="r11" bitsize="8" type="int"/>
> +  <reg name="r12" bitsize="8" type="int"/>
> +  <reg name="r13" bitsize="8" type="int"/>
> +  <reg name="r14" bitsize="8" type="int"/>
> +  <reg name="r15" bitsize="8" type="int"/>
> +  <reg name="r16" bitsize="8" type="int"/>
> +  <reg name="r17" bitsize="8" type="int"/>
> +  <reg name="r18" bitsize="8" type="int"/>
> +  <reg name="r19" bitsize="8" type="int"/>
> +  <reg name="r20" bitsize="8" type="int"/>
> +  <reg name="r21" bitsize="8" type="int"/>
> +  <reg name="r22" bitsize="8" type="int"/>
> +  <reg name="r23" bitsize="8" type="int"/>
> +  <reg name="r24" bitsize="8" type="int"/>
> +  <reg name="r25" bitsize="8" type="int"/>
> +  <reg name="r26" bitsize="8" type="int"/>
> +  <reg name="r27" bitsize="8" type="int"/>
> +  <reg name="r28" bitsize="8" type="int"/>
> +  <reg name="r29" bitsize="8" type="int"/>
> +  <reg name="r30" bitsize="8" type="int"/>
> +  <reg name="r31" bitsize="8" type="int"/>
> +  <reg name="sreg" bitsize="8" type="int"/>
> +  <reg name="sp" bitsize="8" type="int"/>
> +  <reg name="pc" bitsize="8" type="int"/>
> +</feature>
> --
> 2.17.2 (Apple Git-113)
>
>
Thomas Huth Nov. 25, 2019, 6:51 p.m. UTC | #5
On 24/11/2019 16.17, Aleksandar Markovic wrote:
> 
> 
> On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com
> <mailto:mrolnik@gmail.com>> wrote:
> 
>     This includes:
>     - CPU data structures
>     - object model classes and functions
>     - migration functions
>     - GDB hooks
> 
>     Co-developed-by: Michael Rolnik <mrolnik@gmail.com
>     <mailto:mrolnik@gmail.com>>
>     Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk
>     <mailto:S.E.Harris@kent.ac.uk>>
>     Signed-off-by: Michael Rolnik <mrolnik@gmail.com
>     <mailto:mrolnik@gmail.com>>
>     Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk
>     <mailto:S.E.Harris@kent.ac.uk>>
>     Signed-off-by: Michael Rolnik <mrolnik@gmail.com
>     <mailto:mrolnik@gmail.com>>
>     Acked-by: Igor Mammedov <imammedo@redhat.com
>     <mailto:imammedo@redhat.com>>
>     ---
>      target/avr/cpu-param.h |  37 +++
>      target/avr/cpu-qom.h   |  54 ++++
>      target/avr/cpu.h       | 253 ++++++++++++++++++
>      target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
>      target/avr/gdbstub.c   |  85 ++++++
>      target/avr/machine.c   | 121 +++++++++
>      gdb-xml/avr-cpu.xml    |  49 ++++
>      7 files changed, 1175 insertions(+)
>      create mode 100644 target/avr/cpu-param.h
>      create mode 100644 target/avr/cpu-qom.h
>      create mode 100644 target/avr/cpu.h
>      create mode 100644 target/avr/cpu.c
>      create mode 100644 target/avr/gdbstub.c
>      create mode 100644 target/avr/machine.c
>      create mode 100644 gdb-xml/avr-cpu.xml
> 
>     diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
>     new file mode 100644
>     index 0000000000..ccd1ea3429
>     --- /dev/null
>     +++ b/target/avr/cpu-param.h
>     @@ -0,0 +1,37 @@
>     +/*
>     + * QEMU AVR CPU
>     + *
>     + * Copyright (c) 2019 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.
>     + *
> 
> 
> I think version 2 would be more fitting to QEMU ovarall license than 2.1
> (see LICENCE file in QEMU root dir).
> 
> Peter, am I right or wrong regarding GPL 2 vs. 2.1 (My interpretation is
> that 2 is the best "default" for new files)? The wording in "LICENSE" is
> frankly not entirely clear, and I see many new files using 2.1.

 Hi Aleksandar,

I think you mix up GPL and LGPL here. This file is licensed under the
LGPL, so version 2.1 is perfectly fine here (see COPYING.LIB in the root
directory). For the GPL, there was never a 2.1, so if it would be GPL,
version 2 would be appropriate. Bit since it's LGPL, 2.1 is better indeed.

 Thomas
Aleksandar Markovic Nov. 25, 2019, 7:06 p.m. UTC | #6
On Mon, Nov 25, 2019 at 7:51 PM Thomas Huth <thuth@redhat.com> wrote:
>
> On 24/11/2019 16.17, Aleksandar Markovic wrote:
> >
> >
> > On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com
> > <mailto:mrolnik@gmail.com>> wrote:
> >
> >     This includes:
> >     - CPU data structures
> >     - object model classes and functions
> >     - migration functions
> >     - GDB hooks
> >
> >     Co-developed-by: Michael Rolnik <mrolnik@gmail.com
> >     <mailto:mrolnik@gmail.com>>
> >     Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk
> >     <mailto:S.E.Harris@kent.ac.uk>>
> >     Signed-off-by: Michael Rolnik <mrolnik@gmail.com
> >     <mailto:mrolnik@gmail.com>>
> >     Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk
> >     <mailto:S.E.Harris@kent.ac.uk>>
> >     Signed-off-by: Michael Rolnik <mrolnik@gmail.com
> >     <mailto:mrolnik@gmail.com>>
> >     Acked-by: Igor Mammedov <imammedo@redhat.com
> >     <mailto:imammedo@redhat.com>>
> >     ---
> >      target/avr/cpu-param.h |  37 +++
> >      target/avr/cpu-qom.h   |  54 ++++
> >      target/avr/cpu.h       | 253 ++++++++++++++++++
> >      target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
> >      target/avr/gdbstub.c   |  85 ++++++
> >      target/avr/machine.c   | 121 +++++++++
> >      gdb-xml/avr-cpu.xml    |  49 ++++
> >      7 files changed, 1175 insertions(+)
> >      create mode 100644 target/avr/cpu-param.h
> >      create mode 100644 target/avr/cpu-qom.h
> >      create mode 100644 target/avr/cpu.h
> >      create mode 100644 target/avr/cpu.c
> >      create mode 100644 target/avr/gdbstub.c
> >      create mode 100644 target/avr/machine.c
> >      create mode 100644 gdb-xml/avr-cpu.xml
> >
> >     diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
> >     new file mode 100644
> >     index 0000000000..ccd1ea3429
> >     --- /dev/null
> >     +++ b/target/avr/cpu-param.h
> >     @@ -0,0 +1,37 @@
> >     +/*
> >     + * QEMU AVR CPU
> >     + *
> >     + * Copyright (c) 2019 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.
> >     + *
> >
> >
> > I think version 2 would be more fitting to QEMU ovarall license than 2.1
> > (see LICENCE file in QEMU root dir).
> >
> > Peter, am I right or wrong regarding GPL 2 vs. 2.1 (My interpretation is
> > that 2 is the best "default" for new files)? The wording in "LICENSE" is
> > frankly not entirely clear, and I see many new files using 2.1.
>
>  Hi Aleksandar,
>
> I think you mix up GPL and LGPL here. This file is licensed under the
> LGPL, so version 2.1 is perfectly fine here (see COPYING.LIB in the root
> directory). For the GPL, there was never a 2.1, so if it would be GPL,
> version 2 would be appropriate. Bit since it's LGPL, 2.1 is better indeed.
>

Thanks, Thomas. I already feel dizzy of this GPL/LGPL thing. :-)

If you find appropriate and feel comfortable about it, you can respond to
my general question on the lis too, where it is also obvious that I mixed up
GPL and LGPL:

https://lists.gnu.org/archive/html/qemu-devel/2019-11/msg04179.html

Yours,
Aleksandar

>  Thomas
>
Aleksandar Markovic Nov. 26, 2019, 1:25 a.m. UTC | #7
On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com> wrote:

> This includes:
> - CPU data structures
> - object model classes and functions
> - migration functions
> - GDB hooks
>
> Co-developed-by: Michael Rolnik <mrolnik@gmail.com>
> Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk>
> Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
> Acked-by: Igor Mammedov <imammedo@redhat.com>
> ---
>  target/avr/cpu-param.h |  37 +++
>  target/avr/cpu-qom.h   |  54 ++++
>  target/avr/cpu.h       | 253 ++++++++++++++++++
>  target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
>  target/avr/gdbstub.c   |  85 ++++++
>  target/avr/machine.c   | 121 +++++++++
>  gdb-xml/avr-cpu.xml    |  49 ++++
>  7 files changed, 1175 insertions(+)
>  create mode 100644 target/avr/cpu-param.h
>  create mode 100644 target/avr/cpu-qom.h
>  create mode 100644 target/avr/cpu.h
>  create mode 100644 target/avr/cpu.c
>  create mode 100644 target/avr/gdbstub.c
>  create mode 100644 target/avr/machine.c
>  create mode 100644 gdb-xml/avr-cpu.xml
>
> diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
> new file mode 100644
> index 0000000000..ccd1ea3429
> --- /dev/null
> +++ b/target/avr/cpu-param.h
> @@ -0,0 +1,37 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_CPU_PARAM_H
> +#define AVR_CPU_PARAM_H 1
> +
> +#define TARGET_LONG_BITS 32
> +/*
> + * 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
> +
> +
> +#endif
> diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h
> new file mode 100644
> index 0000000000..e28b58c897
> --- /dev/null
> +++ b/target/avr/cpu-qom.h
> @@ -0,0 +1,54 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_QOM_H
> +#define QEMU_AVR_QOM_H
> +
> +#include "hw/core/cpu.h"
> +
> +#define TYPE_AVR_CPU "avr-cpu"
> +
> +#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 {
> +    /*< private >*/
> +    CPUClass parent_class;
> +    /*< public >*/
> +    DeviceRealize parent_realize;
> +    void (*parent_reset)(CPUState *cpu);
> +} AVRCPUClass;
> +
> +typedef struct AVRCPU AVRCPU;
> +
> +
> +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */
> diff --git a/target/avr/cpu.h b/target/avr/cpu.h
> new file mode 100644
> index 0000000000..ed9218af5f
> --- /dev/null
> +++ b/target/avr/cpu.h
> @@ -0,0 +1,253 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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_H
> +#define QEMU_AVR_CPU_H
> +
> +#include "cpu-qom.h"
> +#include "exec/cpu-defs.h"
> +
> +#define TCG_GUEST_DEFAULT_MO 0
> +
> +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU
> +
> +/*
> + * AVR has two memory spaces, data & code.
> + * e.g. both have 0 address
> + * ST/LD instructions access data space
> + * LPM/SPM and instruction fetching access code memory space
> + */
> +#define MMU_CODE_IDX 0
> +#define MMU_DATA_IDX 1
> +
> +#define EXCP_RESET 1
> +#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
> +
> +/* Number of CPU registers */
> +#define NO_CPU_REGISTERS 32
> +/* Number of IO registers accessible by ld/st/in/out */
> +#define NO_IO_REGISTERS 64
> +


May I ask you to do a global replace of names of these two constants
to CPU_REGISTERS_COUNT / IO_REGISTERS_COUNT or NUMBER_OF_CPU_REGISTERS
/ NUMBER_OF_IO_REGISTERS, or whatever else you find suitable (the
reason being "NO_" is visually/perceptually very confusing - many
readers would have first impression that it means a negative ("no"),
not a "number of" as you, for sure, want.

Thanks,
Aleksandar


> +/*
> + * Offsets of AVR memory regions in host memory space.
> + *
> + * This is needed because the AVR has separate code and data address
> + * spaces that both have start from zero but have to go somewhere in
> + * host memory.
> + *
> + * It's also useful to know where some things are, like the IO registers.
> + */
> +/* Flash program memory */
> +#define OFFSET_CODE 0x00000000
> +/* CPU registers, IO registers, and SRAM */
> +#define OFFSET_DATA 0x00800000
> +/* CPU registers specifically, these are mapped at the start of data */
> +#define OFFSET_CPU_REGISTERS OFFSET_DATA
> +/*
> + * IO registers, including status register, stack pointer, and memory
> + * mapped peripherals, mapped just after CPU registers
> + */
> +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS)
> +
> +enum avr_features {
> +    AVR_FEATURE_SRAM,
> +
> +    AVR_FEATURE_1_BYTE_PC,
> +    AVR_FEATURE_2_BYTE_PC,
> +    AVR_FEATURE_3_BYTE_PC,
> +
> +    AVR_FEATURE_1_BYTE_SP,
> +    AVR_FEATURE_2_BYTE_SP,
> +
> +    AVR_FEATURE_BREAK,
> +    AVR_FEATURE_DES,
> +    AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
> +
> +    AVR_FEATURE_EIJMP_EICALL,
> +    AVR_FEATURE_IJMP_ICALL,
> +    AVR_FEATURE_JMP_CALL,
> +
> +    AVR_FEATURE_ADIW_SBIW,
> +
> +    AVR_FEATURE_SPM,
> +    AVR_FEATURE_SPMX,
> +
> +    AVR_FEATURE_ELPMX,
> +    AVR_FEATURE_ELPM,
> +    AVR_FEATURE_LPMX,
> +    AVR_FEATURE_LPM,
> +
> +    AVR_FEATURE_MOVW,
> +    AVR_FEATURE_MUL,
> +    AVR_FEATURE_RAMPD,
> +    AVR_FEATURE_RAMPX,
> +    AVR_FEATURE_RAMPY,
> +    AVR_FEATURE_RAMPZ,
> +};
> +
> +typedef struct CPUAVRState CPUAVRState;
> +
> +struct CPUAVRState {
> +    uint32_t pc_w; /* 0x003fffff up to 22 bits */
> +
> +    uint32_t sregC; /* 0x00000001 1 bit */
> +    uint32_t sregZ; /* 0x00000001 1 bit */
> +    uint32_t sregN; /* 0x00000001 1 bit */
> +    uint32_t sregV; /* 0x00000001 1 bit */
> +    uint32_t sregS; /* 0x00000001 1 bit */
> +    uint32_t sregH; /* 0x00000001 1 bit */
> +    uint32_t sregT; /* 0x00000001 1 bit */
> +    uint32_t sregI; /* 0x00000001 1 bit */
> +
> +    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 r[NO_CPU_REGISTERS]; /* 8 bits each */
> +    uint32_t sp; /* 16 bits */
> +
> +    uint32_t skip; /* if set skip instruction */
> +
> +    uint64_t intsrc; /* interrupt sources */
> +    bool fullacc; /* CPU/MEM if true MEM only otherwise */
> +
> +    uint32_t features;
> +};
> +
> +/**
> + *  AVRCPU:
> + *  @env: #CPUAVRState
> + *
> + *  A AVR CPU.
> + */
> +typedef struct AVRCPU {
> +    /*< private >*/
> +    CPUState parent_obj;
> +    /*< public >*/
> +
> +    CPUNegativeOffsetState neg;
> +    CPUAVRState env;
> +} AVRCPU;
> +
> +#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);
> +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);
> +
> +static inline int avr_feature(CPUAVRState *env, int feature)
> +{
> +    return (env->features & (1U << feature)) != 0;
> +}
> +
> +static inline void avr_set_feature(CPUAVRState *env, int feature)
> +{
> +    env->features |= (1U << feature);
> +}
> +
> +#define cpu_list avr_cpu_list
> +#define cpu_signal_handler cpu_avr_signal_handler
> +#define cpu_mmu_index avr_cpu_mmu_index
> +
> +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
> +{
> +    return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
> +}
> +
> +void avr_cpu_tcg_init(void);
> +
> +void avr_cpu_list(void);
> +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 size,
> +                                int rw, int mmu_idx);
> +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
> +                                int len, bool is_write);
> +
> +enum {
> +    TB_FLAGS_FULL_ACCESS = 1,
> +    TB_FLAGS_SKIP = 2,
> +};
> +
> +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong
> *pc,
> +                                target_ulong *cs_base, uint32_t *pflags)
> +{
> +    uint32_t flags = 0;
> +
> +    *pc = env->pc_w * 2;
> +    *cs_base = 0;
> +
> +    if (env->fullacc) {
> +        flags |= TB_FLAGS_FULL_ACCESS;
> +    }
> +    if (env->skip) {
> +        flags |= TB_FLAGS_SKIP;
> +    }
> +
> +    *pflags = flags;
> +}
> +
> +static inline int cpu_interrupts_enabled(CPUAVRState *env)
> +{
> +    return env->sregI != 0;
> +}
> +
> +static inline uint8_t cpu_get_sreg(CPUAVRState *env)
> +{
> +    uint8_t sreg;
> +    sreg = (env->sregC) << 0
> +         | (env->sregZ) << 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;
> +    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;
> +}
> +
> +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> +                        MMUAccessType access_type, int mmu_idx,
> +                        bool probe, uintptr_t retaddr);
> +
> +typedef CPUAVRState CPUArchState;
> +typedef AVRCPU ArchCPU;
> +
> +#include "exec/cpu-all.h"
> +
> +#endif /* !defined (QEMU_AVR_CPU_H) */
> diff --git a/target/avr/cpu.c b/target/avr/cpu.c
> new file mode 100644
> index 0000000000..dae56d7845
> --- /dev/null
> +++ b/target/avr/cpu.c
> @@ -0,0 +1,576 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "qemu/qemu-print.h"
> +#include "exec/exec-all.h"
> +#include "cpu.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 *cs)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
> +    CPUAVRState *env = &cpu->env;
> +
> +    mcc->parent_reset(cs);
> +
> +    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;
> +
> +    env->skip = 0;
> +
> +    memset(env->r, 0, sizeof(env->r));
> +
> +    tlb_flush(cs);
> +}
> +
> +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);
> +    Error *local_err = NULL;
> +
> +    cpu_exec_realizefn(cs, &local_err);
> +    if (local_err != NULL) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    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)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +
> +    cpu_set_cpustate_pointers(cpu);
> +
> +#ifndef CONFIG_USER_ONLY
> +    /* Set the number of interrupts supported by the CPU. */
> +    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57);
> +#endif
> +}
> +
> +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
> +{
> +    ObjectClass *oc;
> +
> +    oc = object_class_by_name(cpu_model);
> +    if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL ||
> +        object_class_is_abstract(oc)) {
> +        oc = NULL;
> +    }
> +    return oc;
> +}
> +
> +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> +{
> +    AVRCPU *cpu = AVR_CPU(cs);
> +    CPUAVRState *env = &cpu->env;
> +    int i;
> +
> +    qemu_fprintf(f, "\n");
> +    qemu_fprintf(f, "PC:    %06x\n", env->pc_w);
> +    qemu_fprintf(f, "SP:      %04x\n", env->sp);
> +    qemu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
> +    qemu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
> +    qemu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
> +    qemu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
> +    qemu_fprintf(f, "EIND:      %02x\n", env->eind >> 16);
> +    qemu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
> +    qemu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
> +    qemu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
> +    qemu_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' : '-');
> +    qemu_fprintf(f, "SKIP:    %02x\n", env->skip);
> +
> +    qemu_fprintf(f, "\n");
> +    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
> +        qemu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
> +
> +        if ((i % 8) == 7) {
> +            qemu_fprintf(f, "\n");
> +        }
> +    }
> +    qemu_fprintf(f, "\n");
> +}
> +
> +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->tlb_fill = avr_cpu_tlb_fill;
> +    cc->tcg_initialize = avr_cpu_tcg_init;
> +    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;
> +    cc->gdb_core_xml_file = "avr-cpu.xml";
> +}
> +
> +static void avr_avr1_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +}
> +
> +static void avr_avr2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +}
> +
> +static void avr_avr25_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr3_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr31_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +}
> +
> +static void avr_avr35_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +}
> +
> +static void avr_avr4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr51_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_avr6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +}
> +
> +static void avr_xmega2_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega4_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega5_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega6_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +static void avr_xmega7_initfn(Object *obj)
> +{
> +    AVRCPU *cpu = AVR_CPU(obj);
> +    CPUAVRState *env = &cpu->env;
> +
> +    avr_set_feature(env, AVR_FEATURE_LPM);
> +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
> +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
> +    avr_set_feature(env, AVR_FEATURE_SRAM);
> +    avr_set_feature(env, AVR_FEATURE_BREAK);
> +
> +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
> +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
> +    avr_set_feature(env, AVR_FEATURE_RAMPD);
> +    avr_set_feature(env, AVR_FEATURE_RAMPX);
> +    avr_set_feature(env, AVR_FEATURE_RAMPY);
> +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
> +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
> +    avr_set_feature(env, AVR_FEATURE_ELPMX);
> +    avr_set_feature(env, AVR_FEATURE_ELPM);
> +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
> +    avr_set_feature(env, AVR_FEATURE_LPMX);
> +    avr_set_feature(env, AVR_FEATURE_MOVW);
> +    avr_set_feature(env, AVR_FEATURE_MUL);
> +    avr_set_feature(env, AVR_FEATURE_RMW);
> +}
> +
> +typedef struct AVRCPUInfo {
> +    const char *name;
> +    void (*initfn)(Object *obj);
> +} AVRCPUInfo;
> +
> +
> +static void avr_cpu_list_entry(gpointer data, gpointer user_data)
> +{
> +    const char *typename = object_class_get_name(OBJECT_CLASS(data));
> +
> +    qemu_printf("%s\n", typename);
> +}
> +
> +void avr_cpu_list(void)
> +{
> +    GSList *list;
> +    list = object_class_get_list_sorted(TYPE_AVR_CPU, false);
> +    g_slist_foreach(list, avr_cpu_list_entry, NULL);
> +    g_slist_free(list);
> +}
> +
> +#define DEFINE_AVR_CPU_TYPE(model, initfn) \
> +    { \
> +        .parent = TYPE_AVR_CPU, \
> +        .instance_init = initfn, \
> +        .name = model "-avr-cpu", \
> +    }
> +
> +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,
> +    },
> +    DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn),
> +    DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn),
> +    DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn),
> +};
> +
> +DEFINE_TYPES(avr_cpu_type_info)
> diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
> new file mode 100644
> index 0000000000..20a5252482
> --- /dev/null
> +++ b/target/avr/gdbstub.c
> @@ -0,0 +1,85 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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;
> +
> +    /*  R */
> +    if (n < 32) {
> +        env->r[n] = *mem_buf;
> +        return 1;
> +    }
> +
> +    /*  SREG */
> +    if (n == 32) {
> +        cpu_set_sreg(env, *mem_buf);
> +        return 1;
> +    }
> +
> +    /*  SP */
> +    if (n == 33) {
> +        env->sp = lduw_p(mem_buf);
> +        return 2;
> +    }
> +
> +    /*  PC */
> +    if (n == 34) {
> +        env->pc_w = ldl_p(mem_buf) / 2;
> +        return 4;
> +    }
> +
> +    return 0;
> +}
> diff --git a/target/avr/machine.c b/target/avr/machine.c
> new file mode 100644
> index 0000000000..f6dcda7adc
> --- /dev/null
> +++ b/target/avr/machine.c
> @@ -0,0 +1,121 @@
> +/*
> + * QEMU AVR CPU
> + *
> + * Copyright (c) 2019 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 "migration/cpu.h"
> +
> +static int get_sreg(QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg;
> +
> +    sreg = qemu_get_byte(f);
> +    cpu_set_sreg(env, sreg);
> +    return 0;
> +}
> +
> +static int put_sreg(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    CPUAVRState *env = opaque;
> +    uint8_t sreg = cpu_get_sreg(env);
> +
> +    qemu_put_byte(f, sreg);
> +    return 0;
> +}
> +
> +static const VMStateInfo vms_sreg = {
> +    .name = "sreg",
> +    .get = get_sreg,
> +    .put = put_sreg,
> +};
> +
> +static int get_segment(
> +    QEMUFile *f, void *opaque, size_t size, const VMStateField *field)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp;
> +
> +    temp = qemu_get_byte(f);
> +    *ramp = ((uint32_t)temp) << 16;
> +    return 0;
> +}
> +
> +static int put_segment(
> +    QEMUFile *f, void *opaque, size_t size,
> +    const VMStateField *field, QJSON *vmdesc)
> +{
> +    uint32_t *ramp = opaque;
> +    uint8_t temp = *ramp >> 16;
> +
> +    qemu_put_byte(f, temp);
> +    return 0;
> +}
> +
> +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(env.skip, AVRCPU),
> +
> +        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS),
> +
> +        VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState),
> +        VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t),
> +        VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t),
> +        VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t),
> +        VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t),
> +        VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t),
> +
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml
> new file mode 100644
> index 0000000000..c4747f5b40
> --- /dev/null
> +++ b/gdb-xml/avr-cpu.xml
> @@ -0,0 +1,49 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
> +
> +     Copying and distribution of this file, with or without modification,
> +     are permitted in any medium without royalty provided the copyright
> +     notice and this notice are preserved.  -->
> +
> +<!-- Register numbers are hard-coded in order to maintain backward
> +     compatibility with older versions of tools that didn't use xml
> +     register descriptions.  -->
> +
> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
> +<feature name="org.gnu.gdb.riscv.cpu">
> +  <reg name="r0" bitsize="8" type="int" regnum="0"/>
> +  <reg name="r1" bitsize="8" type="int"/>
> +  <reg name="r2" bitsize="8" type="int"/>
> +  <reg name="r3" bitsize="8" type="int"/>
> +  <reg name="r4" bitsize="8" type="int"/>
> +  <reg name="r5" bitsize="8" type="int"/>
> +  <reg name="r6" bitsize="8" type="int"/>
> +  <reg name="r7" bitsize="8" type="int"/>
> +  <reg name="r8" bitsize="8" type="int"/>
> +  <reg name="r9" bitsize="8" type="int"/>
> +  <reg name="r10" bitsize="8" type="int"/>
> +  <reg name="r11" bitsize="8" type="int"/>
> +  <reg name="r12" bitsize="8" type="int"/>
> +  <reg name="r13" bitsize="8" type="int"/>
> +  <reg name="r14" bitsize="8" type="int"/>
> +  <reg name="r15" bitsize="8" type="int"/>
> +  <reg name="r16" bitsize="8" type="int"/>
> +  <reg name="r17" bitsize="8" type="int"/>
> +  <reg name="r18" bitsize="8" type="int"/>
> +  <reg name="r19" bitsize="8" type="int"/>
> +  <reg name="r20" bitsize="8" type="int"/>
> +  <reg name="r21" bitsize="8" type="int"/>
> +  <reg name="r22" bitsize="8" type="int"/>
> +  <reg name="r23" bitsize="8" type="int"/>
> +  <reg name="r24" bitsize="8" type="int"/>
> +  <reg name="r25" bitsize="8" type="int"/>
> +  <reg name="r26" bitsize="8" type="int"/>
> +  <reg name="r27" bitsize="8" type="int"/>
> +  <reg name="r28" bitsize="8" type="int"/>
> +  <reg name="r29" bitsize="8" type="int"/>
> +  <reg name="r30" bitsize="8" type="int"/>
> +  <reg name="r31" bitsize="8" type="int"/>
> +  <reg name="sreg" bitsize="8" type="int"/>
> +  <reg name="sp" bitsize="8" type="int"/>
> +  <reg name="pc" bitsize="8" type="int"/>
> +</feature>
> --
> 2.17.2 (Apple Git-113)
>
>
Philippe Mathieu-Daudé Nov. 26, 2019, 10:54 p.m. UTC | #8
Hi Aleksandar,

On 11/24/19 5:21 PM, Aleksandar Markovic wrote:
> On Sunday, November 24, 2019, Michael Rolnik <mrolnik@gmail.com 
> <mailto:mrolnik@gmail.com>> wrote:
> 
>     This includes:
>     - CPU data structures
>     - object model classes and functions
>     - migration functions
>     - GDB hooks
> 
>     Co-developed-by: Michael Rolnik <mrolnik@gmail.com
>     <mailto:mrolnik@gmail.com>>
>     Co-developed-by: Sarah Harris <S.E.Harris@kent.ac.uk
>     <mailto:S.E.Harris@kent.ac.uk>>
>     Signed-off-by: Michael Rolnik <mrolnik@gmail.com
>     <mailto:mrolnik@gmail.com>>
>     Signed-off-by: Sarah Harris <S.E.Harris@kent.ac.uk
>     <mailto:S.E.Harris@kent.ac.uk>>
>     Signed-off-by: Michael Rolnik <mrolnik@gmail.com
>     <mailto:mrolnik@gmail.com>>
>     Acked-by: Igor Mammedov <imammedo@redhat.com
>     <mailto:imammedo@redhat.com>>
>     ---
> 
> 
> Unfortunately, it appears to me that support for AVR-specific gdb 
> command "info io_registers" is missing. This command looks very 
> important in overall AVR/gdb context, and I think we shouldn't leave it 
> unsupported. (please prove me wrong if I am mistaken here in any way).
> 
> Cc- ing Alex as he is the maintainer for gdbstub QEMU component, for his 
> opinion and advice.
> 
> Philippe, what happens in your experimental AVR setups, if the gdb 
> command  "info io_registers" is used?

I use gdb-multiarch which doesn't have the AVR target:

$ gdb-multiarch -q
(gdb) set pagination off
(gdb) set architecture <tab>
Display all 200 possibilities? (y or n)y
aarch64                        mips:4120
aarch64:ilp32                  mips:4300
alpha                          mips:4400
alpha:ev4                      mips:4600
alpha:ev5                      mips:4650
alpha:ev6                      mips:5000
arm                            mips:5400
arm_any                        mips:5500
armv2                          mips:5900
armv2a                         mips:6000
armv3                          mips:7000
armv3m                         mips:8000
armv4                          mips:9000
armv4t                         mips:interaptiv-mr2
armv5                          mips:isa32
armv5t                         mips:isa32r2
armv5te                        mips:isa32r3
armv5tej                       mips:isa32r5
armv6                          mips:isa32r6
armv6-m                        mips:isa64
armv6k                         mips:isa64r2
armv6kz                        mips:isa64r3
armv6s-m                       mips:isa64r5
armv6t2                        mips:isa64r6
armv7                          mips:loongson_2e
armv7e-m                       mips:loongson_2f
armv8-a                        mips:loongson_3a
armv8-m.base                   mips:micromips
armv8-m.main                   mips:mips5
armv8-r                        mips:octeon
ep9312                         mips:octeon+
hppa1.0                        mips:octeon2
i386                           mips:octeon3
i386:intel                     mips:sb1
i386:nacl                      mips:xlr
i386:x64-32                    powerpc:403
i386:x64-32:intel              powerpc:601
i386:x64-32:nacl               powerpc:603
i386:x86-64                    powerpc:604
i386:x86-64:intel              powerpc:620
i386:x86-64:nacl               powerpc:630
i8086                          powerpc:7400
ia64-elf32                     powerpc:750
ia64-elf64                     powerpc:EC603e
iwmmxt                         powerpc:MPC8XX
iwmmxt2                        powerpc:a35
m68k                           powerpc:common
m68k:5200                      powerpc:common64
m68k:5206e                     powerpc:e500
m68k:521x                      powerpc:e500mc
m68k:5249                      powerpc:e500mc64
m68k:528x                      powerpc:e5500
m68k:5307                      powerpc:e6500
m68k:5407                      powerpc:rs64ii
m68k:547x                      powerpc:rs64iii
m68k:548x                      powerpc:titan
m68k:68000                     powerpc:vle
m68k:68008                     rs6000:6000
m68k:68010                     rs6000:rs1
m68k:68020                     rs6000:rs2
m68k:68030                     rs6000:rsc
m68k:68040                     s390:31-bit
m68k:68060                     s390:64-bit
m68k:cfv4e                     sh
m68k:cpu32                     sh-dsp
m68k:fido                      sh2
m68k:isa-a                     sh2a
m68k:isa-a:emac                sh2a-nofpu
m68k:isa-a:mac                 sh2a-nofpu-or-sh3-nommu
m68k:isa-a:nodiv               sh2a-nofpu-or-sh4-nommu-nofpu
m68k:isa-aplus                 sh2a-or-sh3e
m68k:isa-aplus:emac            sh2a-or-sh4
m68k:isa-aplus:mac             sh2e
m68k:isa-b                     sh3
m68k:isa-b:emac                sh3-dsp
m68k:isa-b:float               sh3-nommu
m68k:isa-b:float:emac          sh3e
m68k:isa-b:float:mac           sh4
m68k:isa-b:mac                 sh4-nofpu
m68k:isa-b:nousp               sh4-nommu-nofpu
m68k:isa-b:nousp:emac          sh4a
m68k:isa-b:nousp:mac           sh4a-nofpu
m68k:isa-c                     sh4al-dsp
m68k:isa-c:emac                sparc
m68k:isa-c:mac                 sparc:sparclet
m68k:isa-c:nodiv               sparc:sparclite
m68k:isa-c:nodiv:emac          sparc:sparclite_le
m68k:isa-c:nodiv:mac           sparc:v8plus
mips                           sparc:v8plusa
mips:10000                     sparc:v8plusb
mips:12000                     sparc:v8plusc
mips:14000                     sparc:v8plusd
mips:16                        sparc:v8pluse
mips:16000                     sparc:v9
mips:3000                      sparc:v9a
mips:3900                      sparc:v9b
mips:4000                      sparc:v9c
mips:4010                      sparc:v9d
mips:4100                      sparc:v9e
mips:4111                      xscale
*** List may be truncated, max-completions reached. ***
(gdb)

I used trace events to test this port (the FreeRTOS test, and trying to 
boot some Atmega328 firmware.

So for the non-gdb part:
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>

>  From gdb docs:
> 
> 
>         21.3.8 Atmel AVR
> 
> When configured for debugging the Atmel AVR, GDB supports the following 
> AVR-specific commands:
> 
> |info io_registers|
> 
>     This command displays information about the AVR I/O registers. For
>     each register, GDB prints its number and value.
> 
> 
> 
>       target/avr/cpu-param.h |  37 +++
>       target/avr/cpu-qom.h   |  54 ++++
>       target/avr/cpu.h       | 253 ++++++++++++++++++
>       target/avr/cpu.c       | 576 +++++++++++++++++++++++++++++++++++++++++
>       target/avr/gdbstub.c   |  85 ++++++
>       target/avr/machine.c   | 121 +++++++++
>       gdb-xml/avr-cpu.xml    |  49 ++++
>       7 files changed, 1175 insertions(+)
>       create mode 100644 target/avr/cpu-param.h
>       create mode 100644 target/avr/cpu-qom.h
>       create mode 100644 target/avr/cpu.h
>       create mode 100644 target/avr/cpu.c
>       create mode 100644 target/avr/gdbstub.c
>       create mode 100644 target/avr/machine.c
>       create mode 100644 gdb-xml/avr-cpu.xml
> 
>     diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
>     new file mode 100644
>     index 0000000000..ccd1ea3429
>     --- /dev/null
>     +++ b/target/avr/cpu-param.h
>     @@ -0,0 +1,37 @@
>     +/*
>     + * QEMU AVR CPU
>     + *
>     + * Copyright (c) 2019 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
>     <http://www.gnu.org/licenses/lgpl-2.1.html>>
>     + */
>     +
>     +#ifndef AVR_CPU_PARAM_H
>     +#define AVR_CPU_PARAM_H 1
>     +
>     +#define TARGET_LONG_BITS 32
>     +/*
>     + * 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
>     +
>     +
>     +#endif
>     diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h
>     new file mode 100644
>     index 0000000000..e28b58c897
>     --- /dev/null
>     +++ b/target/avr/cpu-qom.h
>     @@ -0,0 +1,54 @@
>     +/*
>     + * QEMU AVR CPU
>     + *
>     + * Copyright (c) 2019 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
>     <http://www.gnu.org/licenses/lgpl-2.1.html>>
>     + */
>     +
>     +#ifndef QEMU_AVR_QOM_H
>     +#define QEMU_AVR_QOM_H
>     +
>     +#include "hw/core/cpu.h"
>     +
>     +#define TYPE_AVR_CPU "avr-cpu"
>     +
>     +#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 {
>     +    /*< private >*/
>     +    CPUClass parent_class;
>     +    /*< public >*/
>     +    DeviceRealize parent_realize;
>     +    void (*parent_reset)(CPUState *cpu);
>     +} AVRCPUClass;
>     +
>     +typedef struct AVRCPU AVRCPU;
>     +
>     +
>     +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */
>     diff --git a/target/avr/cpu.h b/target/avr/cpu.h
>     new file mode 100644
>     index 0000000000..ed9218af5f
>     --- /dev/null
>     +++ b/target/avr/cpu.h
>     @@ -0,0 +1,253 @@
>     +/*
>     + * QEMU AVR CPU
>     + *
>     + * Copyright (c) 2019 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
>     <http://www.gnu.org/licenses/lgpl-2.1.html>>
>     + */
>     +
>     +#ifndef QEMU_AVR_CPU_H
>     +#define QEMU_AVR_CPU_H
>     +
>     +#include "cpu-qom.h"
>     +#include "exec/cpu-defs.h"
>     +
>     +#define TCG_GUEST_DEFAULT_MO 0
>     +
>     +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU
>     +
>     +/*
>     + * AVR has two memory spaces, data & code.
>     + * e.g. both have 0 address
>     + * ST/LD instructions access data space
>     + * LPM/SPM and instruction fetching access code memory space
>     + */
>     +#define MMU_CODE_IDX 0
>     +#define MMU_DATA_IDX 1
>     +
>     +#define EXCP_RESET 1
>     +#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
>     +
>     +/* Number of CPU registers */
>     +#define NO_CPU_REGISTERS 32
>     +/* Number of IO registers accessible by ld/st/in/out */
>     +#define NO_IO_REGISTERS 64
>     +
>     +/*
>     + * Offsets of AVR memory regions in host memory space.
>     + *
>     + * This is needed because the AVR has separate code and data address
>     + * spaces that both have start from zero but have to go somewhere in
>     + * host memory.
>     + *
>     + * It's also useful to know where some things are, like the IO
>     registers.
>     + */
>     +/* Flash program memory */
>     +#define OFFSET_CODE 0x00000000
>     +/* CPU registers, IO registers, and SRAM */
>     +#define OFFSET_DATA 0x00800000
>     +/* CPU registers specifically, these are mapped at the start of data */
>     +#define OFFSET_CPU_REGISTERS OFFSET_DATA
>     +/*
>     + * IO registers, including status register, stack pointer, and memory
>     + * mapped peripherals, mapped just after CPU registers
>     + */
>     +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS)
>     +
>     +enum avr_features {
>     +    AVR_FEATURE_SRAM,
>     +
>     +    AVR_FEATURE_1_BYTE_PC,
>     +    AVR_FEATURE_2_BYTE_PC,
>     +    AVR_FEATURE_3_BYTE_PC,
>     +
>     +    AVR_FEATURE_1_BYTE_SP,
>     +    AVR_FEATURE_2_BYTE_SP,
>     +
>     +    AVR_FEATURE_BREAK,
>     +    AVR_FEATURE_DES,
>     +    AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
>     +
>     +    AVR_FEATURE_EIJMP_EICALL,
>     +    AVR_FEATURE_IJMP_ICALL,
>     +    AVR_FEATURE_JMP_CALL,
>     +
>     +    AVR_FEATURE_ADIW_SBIW,
>     +
>     +    AVR_FEATURE_SPM,
>     +    AVR_FEATURE_SPMX,
>     +
>     +    AVR_FEATURE_ELPMX,
>     +    AVR_FEATURE_ELPM,
>     +    AVR_FEATURE_LPMX,
>     +    AVR_FEATURE_LPM,
>     +
>     +    AVR_FEATURE_MOVW,
>     +    AVR_FEATURE_MUL,
>     +    AVR_FEATURE_RAMPD,
>     +    AVR_FEATURE_RAMPX,
>     +    AVR_FEATURE_RAMPY,
>     +    AVR_FEATURE_RAMPZ,
>     +};
>     +
>     +typedef struct CPUAVRState CPUAVRState;
>     +
>     +struct CPUAVRState {
>     +    uint32_t pc_w; /* 0x003fffff up to 22 bits */
>     +
>     +    uint32_t sregC; /* 0x00000001 1 bit */
>     +    uint32_t sregZ; /* 0x00000001 1 bit */
>     +    uint32_t sregN; /* 0x00000001 1 bit */
>     +    uint32_t sregV; /* 0x00000001 1 bit */
>     +    uint32_t sregS; /* 0x00000001 1 bit */
>     +    uint32_t sregH; /* 0x00000001 1 bit */
>     +    uint32_t sregT; /* 0x00000001 1 bit */
>     +    uint32_t sregI; /* 0x00000001 1 bit */
>     +
>     +    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 r[NO_CPU_REGISTERS]; /* 8 bits each */
>     +    uint32_t sp; /* 16 bits */
>     +
>     +    uint32_t skip; /* if set skip instruction */
>     +
>     +    uint64_t intsrc; /* interrupt sources */
>     +    bool fullacc; /* CPU/MEM if true MEM only otherwise */
>     +
>     +    uint32_t features;
>     +};
>     +
>     +/**
>     + *  AVRCPU:
>     + *  @env: #CPUAVRState
>     + *
>     + *  A AVR CPU.
>     + */
>     +typedef struct AVRCPU {
>     +    /*< private >*/
>     +    CPUState parent_obj;
>     +    /*< public >*/
>     +
>     +    CPUNegativeOffsetState neg;
>     +    CPUAVRState env;
>     +} AVRCPU;
>     +
>     +#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);
>     +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);
>     +
>     +static inline int avr_feature(CPUAVRState *env, int feature)
>     +{
>     +    return (env->features & (1U << feature)) != 0;
>     +}
>     +
>     +static inline void avr_set_feature(CPUAVRState *env, int feature)
>     +{
>     +    env->features |= (1U << feature);
>     +}
>     +
>     +#define cpu_list avr_cpu_list
>     +#define cpu_signal_handler cpu_avr_signal_handler
>     +#define cpu_mmu_index avr_cpu_mmu_index
>     +
>     +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
>     +{
>     +    return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
>     +}
>     +
>     +void avr_cpu_tcg_init(void);
>     +
>     +void avr_cpu_list(void);
>     +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 size,
>     +                                int rw, int mmu_idx);
>     +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
>     +                                int len, bool is_write);
>     +
>     +enum {
>     +    TB_FLAGS_FULL_ACCESS = 1,
>     +    TB_FLAGS_SKIP = 2,
>     +};
>     +
>     +static inline void cpu_get_tb_cpu_state(CPUAVRState *env,
>     target_ulong *pc,
>     +                                target_ulong *cs_base, uint32_t
>     *pflags)
>     +{
>     +    uint32_t flags = 0;
>     +
>     +    *pc = env->pc_w * 2;
>     +    *cs_base = 0;
>     +
>     +    if (env->fullacc) {
>     +        flags |= TB_FLAGS_FULL_ACCESS;
>     +    }
>     +    if (env->skip) {
>     +        flags |= TB_FLAGS_SKIP;
>     +    }
>     +
>     +    *pflags = flags;
>     +}
>     +
>     +static inline int cpu_interrupts_enabled(CPUAVRState *env)
>     +{
>     +    return env->sregI != 0;
>     +}
>     +
>     +static inline uint8_t cpu_get_sreg(CPUAVRState *env)
>     +{
>     +    uint8_t sreg;
>     +    sreg = (env->sregC) << 0
>     +         | (env->sregZ) << 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;
>     +    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;
>     +}
>     +
>     +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>     +                        MMUAccessType access_type, int mmu_idx,
>     +                        bool probe, uintptr_t retaddr);
>     +
>     +typedef CPUAVRState CPUArchState;
>     +typedef AVRCPU ArchCPU;
>     +
>     +#include "exec/cpu-all.h"
>     +
>     +#endif /* !defined (QEMU_AVR_CPU_H) */
>     diff --git a/target/avr/cpu.c b/target/avr/cpu.c
>     new file mode 100644
>     index 0000000000..dae56d7845
>     --- /dev/null
>     +++ b/target/avr/cpu.c
>     @@ -0,0 +1,576 @@
>     +/*
>     + * QEMU AVR CPU
>     + *
>     + * Copyright (c) 2019 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
>     <http://www.gnu.org/licenses/lgpl-2.1.html>>
>     + */
>     +
>     +#include "qemu/osdep.h"
>     +#include "qapi/error.h"
>     +#include "qemu/qemu-print.h"
>     +#include "exec/exec-all.h"
>     +#include "cpu.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 *cs)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(cs);
>     +    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    mcc->parent_reset(cs);
>     +
>     +    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;
>     +
>     +    env->skip = 0;
>     +
>     +    memset(env->r, 0, sizeof(env->r));
>     +
>     +    tlb_flush(cs);
>     +}
>     +
>     +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);
>     +    Error *local_err = NULL;
>     +
>     +    cpu_exec_realizefn(cs, &local_err);
>     +    if (local_err != NULL) {
>     +        error_propagate(errp, local_err);
>     +        return;
>     +    }
>     +    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)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +
>     +    cpu_set_cpustate_pointers(cpu);
>     +
>     +#ifndef CONFIG_USER_ONLY
>     +    /* Set the number of interrupts supported by the CPU. */
>     +    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57);
>     +#endif
>     +}
>     +
>     +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
>     +{
>     +    ObjectClass *oc;
>     +
>     +    oc = object_class_by_name(cpu_model);
>     +    if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL ||
>     +        object_class_is_abstract(oc)) {
>     +        oc = NULL;
>     +    }
>     +    return oc;
>     +}
>     +
>     +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(cs);
>     +    CPUAVRState *env = &cpu->env;
>     +    int i;
>     +
>     +    qemu_fprintf(f, "\n");
>     +    qemu_fprintf(f, "PC:    %06x\n", env->pc_w);
>     +    qemu_fprintf(f, "SP:      %04x\n", env->sp);
>     +    qemu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
>     +    qemu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
>     +    qemu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
>     +    qemu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
>     +    qemu_fprintf(f, "EIND:      %02x\n", env->eind >> 16);
>     +    qemu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
>     +    qemu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
>     +    qemu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
>     +    qemu_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' : '-');
>     +    qemu_fprintf(f, "SKIP:    %02x\n", env->skip);
>     +
>     +    qemu_fprintf(f, "\n");
>     +    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
>     +        qemu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
>     +
>     +        if ((i % 8) == 7) {
>     +            qemu_fprintf(f, "\n");
>     +        }
>     +    }
>     +    qemu_fprintf(f, "\n");
>     +}
>     +
>     +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->tlb_fill = avr_cpu_tlb_fill;
>     +    cc->tcg_initialize = avr_cpu_tcg_init;
>     +    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;
>     +    cc->gdb_core_xml_file = "avr-cpu.xml";
>     +}
>     +
>     +static void avr_avr1_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +}
>     +
>     +static void avr_avr2_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +}
>     +
>     +static void avr_avr25_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +}
>     +
>     +static void avr_avr3_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +}
>     +
>     +static void avr_avr31_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>     +    avr_set_feature(env, AVR_FEATURE_ELPM);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +}
>     +
>     +static void avr_avr35_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +}
>     +
>     +static void avr_avr4_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +}
>     +
>     +static void avr_avr5_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +}
>     +
>     +static void avr_avr51_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>     +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>     +    avr_set_feature(env, AVR_FEATURE_ELPM);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +}
>     +
>     +static void avr_avr6_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>     +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>     +    avr_set_feature(env, AVR_FEATURE_ELPM);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +}
>     +
>     +static void avr_xmega2_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +    avr_set_feature(env, AVR_FEATURE_RMW);
>     +}
>     +
>     +static void avr_xmega4_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>     +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>     +    avr_set_feature(env, AVR_FEATURE_ELPM);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +    avr_set_feature(env, AVR_FEATURE_RMW);
>     +}
>     +
>     +static void avr_xmega5_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPD);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPX);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPY);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>     +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>     +    avr_set_feature(env, AVR_FEATURE_ELPM);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +    avr_set_feature(env, AVR_FEATURE_RMW);
>     +}
>     +
>     +static void avr_xmega6_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>     +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>     +    avr_set_feature(env, AVR_FEATURE_ELPM);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +    avr_set_feature(env, AVR_FEATURE_RMW);
>     +}
>     +
>     +static void avr_xmega7_initfn(Object *obj)
>     +{
>     +    AVRCPU *cpu = AVR_CPU(obj);
>     +    CPUAVRState *env = &cpu->env;
>     +
>     +    avr_set_feature(env, AVR_FEATURE_LPM);
>     +    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
>     +    avr_set_feature(env, AVR_FEATURE_SRAM);
>     +    avr_set_feature(env, AVR_FEATURE_BREAK);
>     +
>     +    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
>     +    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPD);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPX);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPY);
>     +    avr_set_feature(env, AVR_FEATURE_RAMPZ);
>     +    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
>     +    avr_set_feature(env, AVR_FEATURE_ELPMX);
>     +    avr_set_feature(env, AVR_FEATURE_ELPM);
>     +    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
>     +    avr_set_feature(env, AVR_FEATURE_LPMX);
>     +    avr_set_feature(env, AVR_FEATURE_MOVW);
>     +    avr_set_feature(env, AVR_FEATURE_MUL);
>     +    avr_set_feature(env, AVR_FEATURE_RMW);
>     +}
>     +
>     +typedef struct AVRCPUInfo {
>     +    const char *name;
>     +    void (*initfn)(Object *obj);
>     +} AVRCPUInfo;
>     +
>     +
>     +static void avr_cpu_list_entry(gpointer data, gpointer user_data)
>     +{
>     +    const char *typename = object_class_get_name(OBJECT_CLASS(data));
>     +
>     +    qemu_printf("%s\n", typename);
>     +}
>     +
>     +void avr_cpu_list(void)
>     +{
>     +    GSList *list;
>     +    list = object_class_get_list_sorted(TYPE_AVR_CPU, false);
>     +    g_slist_foreach(list, avr_cpu_list_entry, NULL);
>     +    g_slist_free(list);
>     +}
>     +
>     +#define DEFINE_AVR_CPU_TYPE(model, initfn) \
>     +    { \
>     +        .parent = TYPE_AVR_CPU, \
>     +        .instance_init = initfn, \
>     +        .name = model "-avr-cpu", \
>     +    }
>     +
>     +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,
>     +    },
>     +    DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn),
>     +    DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn),
>     +    DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn),
>     +    DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn),
>     +    DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn),
>     +    DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn),
>     +    DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn),
>     +};
>     +
>     +DEFINE_TYPES(avr_cpu_type_info)
>     diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
>     new file mode 100644
>     index 0000000000..20a5252482
>     --- /dev/null
>     +++ b/target/avr/gdbstub.c
>     @@ -0,0 +1,85 @@
>     +/*
>     + * QEMU AVR CPU
>     + *
>     + * Copyright (c) 2019 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
>     <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;
>     +
>     +    /*  R */
>     +    if (n < 32) {
>     +        env->r[n] = *mem_buf;
>     +        return 1;
>     +    }
>     +
>     +    /*  SREG */
>     +    if (n == 32) {
>     +        cpu_set_sreg(env, *mem_buf);
>     +        return 1;
>     +    }
>     +
>     +    /*  SP */
>     +    if (n == 33) {
>     +        env->sp = lduw_p(mem_buf);
>     +        return 2;
>     +    }
>     +
>     +    /*  PC */
>     +    if (n == 34) {
>     +        env->pc_w = ldl_p(mem_buf) / 2;
>     +        return 4;
>     +    }
>     +
>     +    return 0;
>     +}
>     diff --git a/target/avr/machine.c b/target/avr/machine.c
>     new file mode 100644
>     index 0000000000..f6dcda7adc
>     --- /dev/null
>     +++ b/target/avr/machine.c
>     @@ -0,0 +1,121 @@
>     +/*
>     + * QEMU AVR CPU
>     + *
>     + * Copyright (c) 2019 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
>     <http://www.gnu.org/licenses/lgpl-2.1.html>>
>     + */
>     +
>     +#include "qemu/osdep.h"
>     +#include "cpu.h"
>     +#include "migration/cpu.h"
>     +
>     +static int get_sreg(QEMUFile *f, void *opaque, size_t size,
>     +    const VMStateField *field)
>     +{
>     +    CPUAVRState *env = opaque;
>     +    uint8_t sreg;
>     +
>     +    sreg = qemu_get_byte(f);
>     +    cpu_set_sreg(env, sreg);
>     +    return 0;
>     +}
>     +
>     +static int put_sreg(
>     +    QEMUFile *f, void *opaque, size_t size,
>     +    const VMStateField *field, QJSON *vmdesc)
>     +{
>     +    CPUAVRState *env = opaque;
>     +    uint8_t sreg = cpu_get_sreg(env);
>     +
>     +    qemu_put_byte(f, sreg);
>     +    return 0;
>     +}
>     +
>     +static const VMStateInfo vms_sreg = {
>     +    .name = "sreg",
>     +    .get = get_sreg,
>     +    .put = put_sreg,
>     +};
>     +
>     +static int get_segment(
>     +    QEMUFile *f, void *opaque, size_t size, const VMStateField *field)
>     +{
>     +    uint32_t *ramp = opaque;
>     +    uint8_t temp;
>     +
>     +    temp = qemu_get_byte(f);
>     +    *ramp = ((uint32_t)temp) << 16;
>     +    return 0;
>     +}
>     +
>     +static int put_segment(
>     +    QEMUFile *f, void *opaque, size_t size,
>     +    const VMStateField *field, QJSON *vmdesc)
>     +{
>     +    uint32_t *ramp = opaque;
>     +    uint8_t temp = *ramp >> 16;
>     +
>     +    qemu_put_byte(f, temp);
>     +    return 0;
>     +}
>     +
>     +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(env.skip, AVRCPU),
>     +
>     +        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS),
>     +
>     +        VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState),
>     +        VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t),
>     +        VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t),
>     +        VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t),
>     +        VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t),
>     +        VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t),
>     +
>     +        VMSTATE_END_OF_LIST()
>     +    }
>     +};
>     diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml
>     new file mode 100644
>     index 0000000000..c4747f5b40
>     --- /dev/null
>     +++ b/gdb-xml/avr-cpu.xml
>     @@ -0,0 +1,49 @@
>     +<?xml version="1.0"?>
>     +<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
>     +
>     +     Copying and distribution of this file, with or without
>     modification,
>     +     are permitted in any medium without royalty provided the copyright
>     +     notice and this notice are preserved.  -->
>     +
>     +<!-- Register numbers are hard-coded in order to maintain backward
>     +     compatibility with older versions of tools that didn't use xml
>     +     register descriptions.  -->
>     +
>     +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
>     +<feature name="org.gnu.gdb.riscv.cpu">
>     +  <reg name="r0" bitsize="8" type="int" regnum="0"/>
>     +  <reg name="r1" bitsize="8" type="int"/>
>     +  <reg name="r2" bitsize="8" type="int"/>
>     +  <reg name="r3" bitsize="8" type="int"/>
>     +  <reg name="r4" bitsize="8" type="int"/>
>     +  <reg name="r5" bitsize="8" type="int"/>
>     +  <reg name="r6" bitsize="8" type="int"/>
>     +  <reg name="r7" bitsize="8" type="int"/>
>     +  <reg name="r8" bitsize="8" type="int"/>
>     +  <reg name="r9" bitsize="8" type="int"/>
>     +  <reg name="r10" bitsize="8" type="int"/>
>     +  <reg name="r11" bitsize="8" type="int"/>
>     +  <reg name="r12" bitsize="8" type="int"/>
>     +  <reg name="r13" bitsize="8" type="int"/>
>     +  <reg name="r14" bitsize="8" type="int"/>
>     +  <reg name="r15" bitsize="8" type="int"/>
>     +  <reg name="r16" bitsize="8" type="int"/>
>     +  <reg name="r17" bitsize="8" type="int"/>
>     +  <reg name="r18" bitsize="8" type="int"/>
>     +  <reg name="r19" bitsize="8" type="int"/>
>     +  <reg name="r20" bitsize="8" type="int"/>
>     +  <reg name="r21" bitsize="8" type="int"/>
>     +  <reg name="r22" bitsize="8" type="int"/>
>     +  <reg name="r23" bitsize="8" type="int"/>
>     +  <reg name="r24" bitsize="8" type="int"/>
>     +  <reg name="r25" bitsize="8" type="int"/>
>     +  <reg name="r26" bitsize="8" type="int"/>
>     +  <reg name="r27" bitsize="8" type="int"/>
>     +  <reg name="r28" bitsize="8" type="int"/>
>     +  <reg name="r29" bitsize="8" type="int"/>
>     +  <reg name="r30" bitsize="8" type="int"/>
>     +  <reg name="r31" bitsize="8" type="int"/>
>     +  <reg name="sreg" bitsize="8" type="int"/>
>     +  <reg name="sp" bitsize="8" type="int"/>
>     +  <reg name="pc" bitsize="8" type="int"/>
>     +</feature>
>     -- 
>     2.17.2 (Apple Git-113)
>
diff mbox series

Patch

diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h
new file mode 100644
index 0000000000..ccd1ea3429
--- /dev/null
+++ b/target/avr/cpu-param.h
@@ -0,0 +1,37 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2019 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_CPU_PARAM_H
+#define AVR_CPU_PARAM_H 1
+
+#define TARGET_LONG_BITS 32
+/*
+ * 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
+
+
+#endif
diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h
new file mode 100644
index 0000000000..e28b58c897
--- /dev/null
+++ b/target/avr/cpu-qom.h
@@ -0,0 +1,54 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2019 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_QOM_H
+#define QEMU_AVR_QOM_H
+
+#include "hw/core/cpu.h"
+
+#define TYPE_AVR_CPU "avr-cpu"
+
+#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 {
+    /*< private >*/
+    CPUClass parent_class;
+    /*< public >*/
+    DeviceRealize parent_realize;
+    void (*parent_reset)(CPUState *cpu);
+} AVRCPUClass;
+
+typedef struct AVRCPU AVRCPU;
+
+
+#endif /* !defined (QEMU_AVR_CPU_QOM_H) */
diff --git a/target/avr/cpu.h b/target/avr/cpu.h
new file mode 100644
index 0000000000..ed9218af5f
--- /dev/null
+++ b/target/avr/cpu.h
@@ -0,0 +1,253 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2019 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_H
+#define QEMU_AVR_CPU_H
+
+#include "cpu-qom.h"
+#include "exec/cpu-defs.h"
+
+#define TCG_GUEST_DEFAULT_MO 0
+
+#define CPU_RESOLVING_TYPE TYPE_AVR_CPU
+
+/*
+ * AVR has two memory spaces, data & code.
+ * e.g. both have 0 address
+ * ST/LD instructions access data space
+ * LPM/SPM and instruction fetching access code memory space
+ */
+#define MMU_CODE_IDX 0
+#define MMU_DATA_IDX 1
+
+#define EXCP_RESET 1
+#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
+
+/* Number of CPU registers */
+#define NO_CPU_REGISTERS 32
+/* Number of IO registers accessible by ld/st/in/out */
+#define NO_IO_REGISTERS 64
+
+/*
+ * Offsets of AVR memory regions in host memory space.
+ *
+ * This is needed because the AVR has separate code and data address
+ * spaces that both have start from zero but have to go somewhere in
+ * host memory.
+ *
+ * It's also useful to know where some things are, like the IO registers.
+ */
+/* Flash program memory */
+#define OFFSET_CODE 0x00000000
+/* CPU registers, IO registers, and SRAM */
+#define OFFSET_DATA 0x00800000
+/* CPU registers specifically, these are mapped at the start of data */
+#define OFFSET_CPU_REGISTERS OFFSET_DATA
+/*
+ * IO registers, including status register, stack pointer, and memory
+ * mapped peripherals, mapped just after CPU registers
+ */
+#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS)
+
+enum avr_features {
+    AVR_FEATURE_SRAM,
+
+    AVR_FEATURE_1_BYTE_PC,
+    AVR_FEATURE_2_BYTE_PC,
+    AVR_FEATURE_3_BYTE_PC,
+
+    AVR_FEATURE_1_BYTE_SP,
+    AVR_FEATURE_2_BYTE_SP,
+
+    AVR_FEATURE_BREAK,
+    AVR_FEATURE_DES,
+    AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
+
+    AVR_FEATURE_EIJMP_EICALL,
+    AVR_FEATURE_IJMP_ICALL,
+    AVR_FEATURE_JMP_CALL,
+
+    AVR_FEATURE_ADIW_SBIW,
+
+    AVR_FEATURE_SPM,
+    AVR_FEATURE_SPMX,
+
+    AVR_FEATURE_ELPMX,
+    AVR_FEATURE_ELPM,
+    AVR_FEATURE_LPMX,
+    AVR_FEATURE_LPM,
+
+    AVR_FEATURE_MOVW,
+    AVR_FEATURE_MUL,
+    AVR_FEATURE_RAMPD,
+    AVR_FEATURE_RAMPX,
+    AVR_FEATURE_RAMPY,
+    AVR_FEATURE_RAMPZ,
+};
+
+typedef struct CPUAVRState CPUAVRState;
+
+struct CPUAVRState {
+    uint32_t pc_w; /* 0x003fffff up to 22 bits */
+
+    uint32_t sregC; /* 0x00000001 1 bit */
+    uint32_t sregZ; /* 0x00000001 1 bit */
+    uint32_t sregN; /* 0x00000001 1 bit */
+    uint32_t sregV; /* 0x00000001 1 bit */
+    uint32_t sregS; /* 0x00000001 1 bit */
+    uint32_t sregH; /* 0x00000001 1 bit */
+    uint32_t sregT; /* 0x00000001 1 bit */
+    uint32_t sregI; /* 0x00000001 1 bit */
+
+    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 r[NO_CPU_REGISTERS]; /* 8 bits each */
+    uint32_t sp; /* 16 bits */
+
+    uint32_t skip; /* if set skip instruction */
+
+    uint64_t intsrc; /* interrupt sources */
+    bool fullacc; /* CPU/MEM if true MEM only otherwise */
+
+    uint32_t features;
+};
+
+/**
+ *  AVRCPU:
+ *  @env: #CPUAVRState
+ *
+ *  A AVR CPU.
+ */
+typedef struct AVRCPU {
+    /*< private >*/
+    CPUState parent_obj;
+    /*< public >*/
+
+    CPUNegativeOffsetState neg;
+    CPUAVRState env;
+} AVRCPU;
+
+#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);
+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);
+
+static inline int avr_feature(CPUAVRState *env, int feature)
+{
+    return (env->features & (1U << feature)) != 0;
+}
+
+static inline void avr_set_feature(CPUAVRState *env, int feature)
+{
+    env->features |= (1U << feature);
+}
+
+#define cpu_list avr_cpu_list
+#define cpu_signal_handler cpu_avr_signal_handler
+#define cpu_mmu_index avr_cpu_mmu_index
+
+static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
+{
+    return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX;
+}
+
+void avr_cpu_tcg_init(void);
+
+void avr_cpu_list(void);
+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 size,
+                                int rw, int mmu_idx);
+int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
+                                int len, bool is_write);
+
+enum {
+    TB_FLAGS_FULL_ACCESS = 1,
+    TB_FLAGS_SKIP = 2,
+};
+
+static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc,
+                                target_ulong *cs_base, uint32_t *pflags)
+{
+    uint32_t flags = 0;
+
+    *pc = env->pc_w * 2;
+    *cs_base = 0;
+
+    if (env->fullacc) {
+        flags |= TB_FLAGS_FULL_ACCESS;
+    }
+    if (env->skip) {
+        flags |= TB_FLAGS_SKIP;
+    }
+
+    *pflags = flags;
+}
+
+static inline int cpu_interrupts_enabled(CPUAVRState *env)
+{
+    return env->sregI != 0;
+}
+
+static inline uint8_t cpu_get_sreg(CPUAVRState *env)
+{
+    uint8_t sreg;
+    sreg = (env->sregC) << 0
+         | (env->sregZ) << 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;
+    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;
+}
+
+bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                        MMUAccessType access_type, int mmu_idx,
+                        bool probe, uintptr_t retaddr);
+
+typedef CPUAVRState CPUArchState;
+typedef AVRCPU ArchCPU;
+
+#include "exec/cpu-all.h"
+
+#endif /* !defined (QEMU_AVR_CPU_H) */
diff --git a/target/avr/cpu.c b/target/avr/cpu.c
new file mode 100644
index 0000000000..dae56d7845
--- /dev/null
+++ b/target/avr/cpu.c
@@ -0,0 +1,576 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2019 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 "qemu/qemu-print.h"
+#include "exec/exec-all.h"
+#include "cpu.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 *cs)
+{
+    AVRCPU *cpu = AVR_CPU(cs);
+    AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
+    CPUAVRState *env = &cpu->env;
+
+    mcc->parent_reset(cs);
+
+    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;
+
+    env->skip = 0;
+
+    memset(env->r, 0, sizeof(env->r));
+
+    tlb_flush(cs);
+}
+
+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);
+    Error *local_err = NULL;
+
+    cpu_exec_realizefn(cs, &local_err);
+    if (local_err != NULL) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    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)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+
+    cpu_set_cpustate_pointers(cpu);
+
+#ifndef CONFIG_USER_ONLY
+    /* Set the number of interrupts supported by the CPU. */
+    qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57);
+#endif
+}
+
+static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+
+    oc = object_class_by_name(cpu_model);
+    if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL ||
+        object_class_is_abstract(oc)) {
+        oc = NULL;
+    }
+    return oc;
+}
+
+static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+    AVRCPU *cpu = AVR_CPU(cs);
+    CPUAVRState *env = &cpu->env;
+    int i;
+
+    qemu_fprintf(f, "\n");
+    qemu_fprintf(f, "PC:    %06x\n", env->pc_w);
+    qemu_fprintf(f, "SP:      %04x\n", env->sp);
+    qemu_fprintf(f, "rampD:     %02x\n", env->rampD >> 16);
+    qemu_fprintf(f, "rampX:     %02x\n", env->rampX >> 16);
+    qemu_fprintf(f, "rampY:     %02x\n", env->rampY >> 16);
+    qemu_fprintf(f, "rampZ:     %02x\n", env->rampZ >> 16);
+    qemu_fprintf(f, "EIND:      %02x\n", env->eind >> 16);
+    qemu_fprintf(f, "X:       %02x%02x\n", env->r[27], env->r[26]);
+    qemu_fprintf(f, "Y:       %02x%02x\n", env->r[29], env->r[28]);
+    qemu_fprintf(f, "Z:       %02x%02x\n", env->r[31], env->r[30]);
+    qemu_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' : '-');
+    qemu_fprintf(f, "SKIP:    %02x\n", env->skip);
+
+    qemu_fprintf(f, "\n");
+    for (i = 0; i < ARRAY_SIZE(env->r); i++) {
+        qemu_fprintf(f, "R[%02d]:  %02x   ", i, env->r[i]);
+
+        if ((i % 8) == 7) {
+            qemu_fprintf(f, "\n");
+        }
+    }
+    qemu_fprintf(f, "\n");
+}
+
+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->tlb_fill = avr_cpu_tlb_fill;
+    cc->tcg_initialize = avr_cpu_tcg_init;
+    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;
+    cc->gdb_core_xml_file = "avr-cpu.xml";
+}
+
+static void avr_avr1_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+}
+
+static void avr_avr2_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+}
+
+static void avr_avr25_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+}
+
+static void avr_avr3_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+}
+
+static void avr_avr31_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_RAMPZ);
+    avr_set_feature(env, AVR_FEATURE_ELPM);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+}
+
+static void avr_avr35_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+}
+
+static void avr_avr4_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr5_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr51_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_RAMPZ);
+    avr_set_feature(env, AVR_FEATURE_ELPMX);
+    avr_set_feature(env, AVR_FEATURE_ELPM);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr6_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_RAMPZ);
+    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+    avr_set_feature(env, AVR_FEATURE_ELPMX);
+    avr_set_feature(env, AVR_FEATURE_ELPM);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_xmega2_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+    avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega4_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_RAMPZ);
+    avr_set_feature(env, AVR_FEATURE_ELPMX);
+    avr_set_feature(env, AVR_FEATURE_ELPM);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+    avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega5_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_RAMPD);
+    avr_set_feature(env, AVR_FEATURE_RAMPX);
+    avr_set_feature(env, AVR_FEATURE_RAMPY);
+    avr_set_feature(env, AVR_FEATURE_RAMPZ);
+    avr_set_feature(env, AVR_FEATURE_ELPMX);
+    avr_set_feature(env, AVR_FEATURE_ELPM);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+    avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega6_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_RAMPZ);
+    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+    avr_set_feature(env, AVR_FEATURE_ELPMX);
+    avr_set_feature(env, AVR_FEATURE_ELPM);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+    avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega7_initfn(Object *obj)
+{
+    AVRCPU *cpu = AVR_CPU(obj);
+    CPUAVRState *env = &cpu->env;
+
+    avr_set_feature(env, AVR_FEATURE_LPM);
+    avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+    avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+    avr_set_feature(env, AVR_FEATURE_SRAM);
+    avr_set_feature(env, AVR_FEATURE_BREAK);
+
+    avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+    avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+    avr_set_feature(env, AVR_FEATURE_RAMPD);
+    avr_set_feature(env, AVR_FEATURE_RAMPX);
+    avr_set_feature(env, AVR_FEATURE_RAMPY);
+    avr_set_feature(env, AVR_FEATURE_RAMPZ);
+    avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+    avr_set_feature(env, AVR_FEATURE_ELPMX);
+    avr_set_feature(env, AVR_FEATURE_ELPM);
+    avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+    avr_set_feature(env, AVR_FEATURE_LPMX);
+    avr_set_feature(env, AVR_FEATURE_MOVW);
+    avr_set_feature(env, AVR_FEATURE_MUL);
+    avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+typedef struct AVRCPUInfo {
+    const char *name;
+    void (*initfn)(Object *obj);
+} AVRCPUInfo;
+
+
+static void avr_cpu_list_entry(gpointer data, gpointer user_data)
+{
+    const char *typename = object_class_get_name(OBJECT_CLASS(data));
+
+    qemu_printf("%s\n", typename);
+}
+
+void avr_cpu_list(void)
+{
+    GSList *list;
+    list = object_class_get_list_sorted(TYPE_AVR_CPU, false);
+    g_slist_foreach(list, avr_cpu_list_entry, NULL);
+    g_slist_free(list);
+}
+
+#define DEFINE_AVR_CPU_TYPE(model, initfn) \
+    { \
+        .parent = TYPE_AVR_CPU, \
+        .instance_init = initfn, \
+        .name = model "-avr-cpu", \
+    }
+
+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,
+    },
+    DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn),
+    DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn),
+    DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn),
+    DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn),
+    DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn),
+    DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn),
+    DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn),
+    DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn),
+    DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn),
+    DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn),
+    DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn),
+    DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn),
+    DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn),
+    DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn),
+    DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn),
+};
+
+DEFINE_TYPES(avr_cpu_type_info)
diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
new file mode 100644
index 0000000000..20a5252482
--- /dev/null
+++ b/target/avr/gdbstub.c
@@ -0,0 +1,85 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2019 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;
+
+    /*  R */
+    if (n < 32) {
+        env->r[n] = *mem_buf;
+        return 1;
+    }
+
+    /*  SREG */
+    if (n == 32) {
+        cpu_set_sreg(env, *mem_buf);
+        return 1;
+    }
+
+    /*  SP */
+    if (n == 33) {
+        env->sp = lduw_p(mem_buf);
+        return 2;
+    }
+
+    /*  PC */
+    if (n == 34) {
+        env->pc_w = ldl_p(mem_buf) / 2;
+        return 4;
+    }
+
+    return 0;
+}
diff --git a/target/avr/machine.c b/target/avr/machine.c
new file mode 100644
index 0000000000..f6dcda7adc
--- /dev/null
+++ b/target/avr/machine.c
@@ -0,0 +1,121 @@ 
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2019 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 "migration/cpu.h"
+
+static int get_sreg(QEMUFile *f, void *opaque, size_t size,
+    const VMStateField *field)
+{
+    CPUAVRState *env = opaque;
+    uint8_t sreg;
+
+    sreg = qemu_get_byte(f);
+    cpu_set_sreg(env, sreg);
+    return 0;
+}
+
+static int put_sreg(
+    QEMUFile *f, void *opaque, size_t size,
+    const VMStateField *field, QJSON *vmdesc)
+{
+    CPUAVRState *env = opaque;
+    uint8_t sreg = cpu_get_sreg(env);
+
+    qemu_put_byte(f, sreg);
+    return 0;
+}
+
+static const VMStateInfo vms_sreg = {
+    .name = "sreg",
+    .get = get_sreg,
+    .put = put_sreg,
+};
+
+static int get_segment(
+    QEMUFile *f, void *opaque, size_t size, const VMStateField *field)
+{
+    uint32_t *ramp = opaque;
+    uint8_t temp;
+
+    temp = qemu_get_byte(f);
+    *ramp = ((uint32_t)temp) << 16;
+    return 0;
+}
+
+static int put_segment(
+    QEMUFile *f, void *opaque, size_t size,
+    const VMStateField *field, QJSON *vmdesc)
+{
+    uint32_t *ramp = opaque;
+    uint8_t temp = *ramp >> 16;
+
+    qemu_put_byte(f, temp);
+    return 0;
+}
+
+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(env.skip, AVRCPU),
+
+        VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS),
+
+        VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState),
+        VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t),
+        VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t),
+        VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t),
+        VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t),
+        VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml
new file mode 100644
index 0000000000..c4747f5b40
--- /dev/null
+++ b/gdb-xml/avr-cpu.xml
@@ -0,0 +1,49 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!-- Register numbers are hard-coded in order to maintain backward
+     compatibility with older versions of tools that didn't use xml
+     register descriptions.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.riscv.cpu">
+  <reg name="r0" bitsize="8" type="int" regnum="0"/>
+  <reg name="r1" bitsize="8" type="int"/>
+  <reg name="r2" bitsize="8" type="int"/>
+  <reg name="r3" bitsize="8" type="int"/>
+  <reg name="r4" bitsize="8" type="int"/>
+  <reg name="r5" bitsize="8" type="int"/>
+  <reg name="r6" bitsize="8" type="int"/>
+  <reg name="r7" bitsize="8" type="int"/>
+  <reg name="r8" bitsize="8" type="int"/>
+  <reg name="r9" bitsize="8" type="int"/>
+  <reg name="r10" bitsize="8" type="int"/>
+  <reg name="r11" bitsize="8" type="int"/>
+  <reg name="r12" bitsize="8" type="int"/>
+  <reg name="r13" bitsize="8" type="int"/>
+  <reg name="r14" bitsize="8" type="int"/>
+  <reg name="r15" bitsize="8" type="int"/>
+  <reg name="r16" bitsize="8" type="int"/>
+  <reg name="r17" bitsize="8" type="int"/>
+  <reg name="r18" bitsize="8" type="int"/>
+  <reg name="r19" bitsize="8" type="int"/>
+  <reg name="r20" bitsize="8" type="int"/>
+  <reg name="r21" bitsize="8" type="int"/>
+  <reg name="r22" bitsize="8" type="int"/>
+  <reg name="r23" bitsize="8" type="int"/>
+  <reg name="r24" bitsize="8" type="int"/>
+  <reg name="r25" bitsize="8" type="int"/>
+  <reg name="r26" bitsize="8" type="int"/>
+  <reg name="r27" bitsize="8" type="int"/>
+  <reg name="r28" bitsize="8" type="int"/>
+  <reg name="r29" bitsize="8" type="int"/>
+  <reg name="r30" bitsize="8" type="int"/>
+  <reg name="r31" bitsize="8" type="int"/>
+  <reg name="sreg" bitsize="8" type="int"/>
+  <reg name="sp" bitsize="8" type="int"/>
+  <reg name="pc" bitsize="8" type="int"/>
+</feature>