diff mbox

[2/2,RFC] add emulation of at91sam9263 cpu

Message ID 20091115204930.GA25677@rain
State New
Headers show

Commit Message

Evgeniy Dushistov Nov. 15, 2009, 8:49 p.m. UTC
add emulation of at91sam9263 cpu, plus sdram, plus nor flash connected to this cpu


Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru>
---
 Makefile.target       |    2 +-
 hw/at91sam9.c         |  695 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/at91sam9263_defs.h |  144 ++++++++++
 3 files changed, 840 insertions(+), 1 deletions(-)
 create mode 100644 hw/at91sam9.c
 create mode 100644 hw/at91sam9263_defs.h

Comments

Filip Navara Nov. 17, 2009, 9:39 a.m. UTC | #1
I'd say it is preferable to split the individual devices and model
them using the QDEV infrastructure instead of putting it all together
into one "system controller" device.

I've QDEV-based implementation of these devices already: PMC, DBGU,
PIO, PITC, AIC. That leaves the "bus matrix", SDRAM controller and
USART (which is very similar to DBGU) to be split up.

Best regards,
Filip Navara

On Sun, Nov 15, 2009 at 9:49 PM, Evgeniy Dushistov <dushistov@mail.ru> wrote:
> add emulation of at91sam9263 cpu, plus sdram, plus nor flash connected to this cpu
>
>
> Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru>
> ---
>  Makefile.target       |    2 +-
>  hw/at91sam9.c         |  695 +++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/at91sam9263_defs.h |  144 ++++++++++
>  3 files changed, 840 insertions(+), 1 deletions(-)
>  create mode 100644 hw/at91sam9.c
>  create mode 100644 hw/at91sam9263_defs.h
>
> diff --git a/Makefile.target b/Makefile.target
> index 7542199..67f441d 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -268,7 +268,7 @@ obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
>  endif
>
>  obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o
> -obj-arm-y += pflash_atmel.o
> +obj-arm-y += pflash_atmel.o at91sam9.o
>  obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
>  obj-arm-y += versatile_pci.o
>  obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o
> diff --git a/hw/at91sam9.c b/hw/at91sam9.c
> new file mode 100644
> index 0000000..7ac60d9
> --- /dev/null
> +++ b/hw/at91sam9.c
> @@ -0,0 +1,695 @@
> +/*
> + * Atmel at91sam9263 cpu + NOR flash + SDRAM emulation
> + * Written by Evgeniy Dushistov
> + * This code is licenced under the GPL.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include "hw.h"
> +#include "arm-misc.h"
> +#include "primecell.h"
> +#include "devices.h"
> +#include "net.h"
> +#include "sysemu.h"
> +#include "flash.h"
> +#include "boards.h"
> +#include "qemu-char.h"
> +#include "qemu-timer.h"
> +
> +#include "at91sam9263_defs.h"
> +
> +//#define AT91_TRACE_ON
> +//#define AT91_DEBUG_ON
> +
> +#define ARM_AIC_CPU_IRQ 0
> +#define ARM_AIC_CPU_FIQ 1
> +
> +#define NOR_FLASH_SIZE (1024 * 1024 * 8)
> +#define AT91SAM9263EK_SDRAM_SIZE (1024 * 1024 * 64)
> +#define AT91SAM9263EK_SDRAM_OFF 0x20000000
> +#define AT91SAM9263EK_NORFLASH_OFF 0x10000000
> +
> +#ifdef AT91_DEBUG_ON
> +#       define DEBUG(f, a...)    {              \
> +        printf ("at91 (%s, %d): %s:",           \
> +                __FILE__, __LINE__, __func__);  \
> +        printf (f, ## a);                       \
> +    }
> +#else
> +#       define DEBUG(f, a...) do { } while (0)
> +#endif
> +
> +#ifdef AT91_TRACE_ON
> +static FILE *trace_file;
> +#       define TRACE(f, a...)    do {           \
> +        fprintf (trace_file, f, ## a);          \
> +    } while (0)
> +#else
> +#       define TRACE(f, a...) do { } while (0)
> +#endif
> +
> +
> +struct dbgu_state {
> +    CharDriverState *chr;
> +};
> +
> +struct at91sam9_state {
> +    uint32_t pmc_regs[28];
> +    uint32_t dbgu_regs[0x124 / 4];
> +    uint32_t bus_matrix_regs[0x100 / 4];
> +    uint32_t ccfg_regs[(0x01FC - 0x0110 + 1) / sizeof(uint32_t)];
> +    uint32_t pio_regs[(AT91_PMC_BASE - AT91_PIO_BASE) / sizeof(uint32_t)];
> +    uint32_t sdramc0_regs[(AT91_SMC0_BASE - AT91_SDRAMC0_BASE) / sizeof(uint32_t)];
> +    uint32_t smc0_regs[(AT91_ECC1_BASE - AT91_SMC0_BASE) / sizeof(uint32_t)];
> +    uint32_t pitc_regs[80];
> +    uint32_t aic_regs[(AT91_PIO_BASE - AT91_AIC_BASE) / sizeof(uint32_t)];
> +    uint32_t usart0_regs[0x1000 / sizeof(uint32_t)];
> +    struct dbgu_state dbgu;
> +    pflash_t *norflash;
> +    ram_addr_t internal_sram;
> +    QEMUTimer *dbgu_tr_timer;
> +    ptimer_state *pitc_timer;
> +    int timer_active;
> +    CPUState *env;
> +    qemu_irq *qirq;
> +    uint64_t char_transmit_time;
> +};
> +
> +static uint32_t at91_pmc_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    TRACE("pmc read offset %X\n", offset);
> +    return sam9->pmc_regs[offset / 4];
> +}
> +
> +static void at91_pmc_write(void *opaque, target_phys_addr_t offset,
> +                           uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("pmc write offset %X, value %X\n", offset, value);
> +    switch (offset / 4) {
> +    case AT91_PMC_MCKR:
> +        sam9->pmc_regs[AT91_PMC_MCKR] = value;
> +        switch (value & AT91_PMC_CSS) {
> +        case 1:
> +            //Main clock is selected
> +            sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MCKRDY | AT91_PMC_MOSCS;
> +            break;
> +        default:
> +            DEBUG("unimplemented\n");
> +            break;
> +        }
> +        break;
> +    case AT91_PMC_MOR:
> +        sam9->pmc_regs[AT91_PMC_MOR] = value;
> +        if (value & 1) {
> +            sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MOSCS;
> +        }
> +        break;
> +    case AT91_PMC_PLLAR:
> +        sam9->pmc_regs[AT91_PMC_PLLAR] = value;
> +        sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKA;
> +        break;
> +    case AT91_PMC_PLLBR:
> +        sam9->pmc_regs[AT91_PMC_PLLBR] = value;
> +        sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKB;
> +        break;
> +    case AT91_PMC_PCER:
> +        sam9->pmc_regs[AT91_PMC_PCER] |= value;
> +        break;
> +    default:
> +        //DEBUG("unimplemented, offset %X\n", offset);
> +        break;
> +    }
> +}
> +
> +static uint32_t at91_dbgu_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    offset /= 4;
> +    if (offset == AT91_DBGU_RHR) {
> +        sam9->dbgu_regs[AT91_DBGU_SR] &= (uint32_t)~1;
> +    }/* else if (offset == AT91_DBGU_SR)*/
> +
> +    return sam9->dbgu_regs[offset];
> +}
> +
> +static void at91_dbgu_state_changed(struct at91sam9_state *sam9)
> +{
> +    if ((sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) &&
> +        (sam9->dbgu_regs[AT91_DBGU_IMR] & sam9->dbgu_regs[AT91_DBGU_SR])) {
> +        sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID;
> +        sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID];
> +        qemu_irq_raise(sam9->qirq[0]);
> +    }
> +}
> +
> +static void dbgu_serial_end_xmit(void *opaque)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    sam9->dbgu_regs[AT91_DBGU_SR] |= (AT91_US_TXEMPTY | AT91_US_TXRDY);
> +    at91_dbgu_state_changed(sam9);
> +}
> +
> +static void at91_dbgu_write(void *opaque, target_phys_addr_t offset,
> +                            uint32_t value)
> +{
> +    unsigned char ch;
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    switch (offset / 4) {
> +    case AT91_DBGU_CR:
> +        sam9->dbgu_regs[AT91_DBGU_CR] = value;
> +        if (value & AT91_US_TXEN)
> +            sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_TXRDY | AT91_US_TXEMPTY;
> +        if (value & AT91_US_TXDIS)
> +            sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXRDY | AT91_US_TXEMPTY);
> +        break;
> +    case AT91_DBGU_IER:
> +        sam9->dbgu_regs[AT91_DBGU_IMR] |= value;
> +        at91_dbgu_state_changed(sam9);
> +        break;
> +    case AT91_DBGU_IDR:
> +        sam9->dbgu_regs[AT91_DBGU_IMR] &= ~value;
> +        break;
> +    case AT91_DBGU_THR:
> +        sam9->dbgu_regs[AT91_DBGU_THR] = value;
> +        sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXEMPTY | AT91_US_TXRDY);
> +        ch = value;
> +        if (sam9->dbgu.chr)
> +            qemu_chr_write(sam9->dbgu.chr, &ch, 1);
> +        qemu_mod_timer(sam9->dbgu_tr_timer , qemu_get_clock(vm_clock) + sam9->char_transmit_time);
> +        break;
> +    default:
> +        //DEBUG("unimplemented\n");
> +        break;
> +    }
> +}
> +
> +static int at91_dbgu_can_receive(void *opaque)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    return (sam9->dbgu_regs[AT91_DBGU_SR] & AT91_US_RXRDY) == 0;
> +}
> +
> +static void at91_dbgu_receive(void *opaque, const uint8_t *buf, int size)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    int i;
> +    /*! \todo if not one character we need wait before irq handled,
> +      but from other hand at91_dbgu_can_receive should prevent this
> +     */
> +    for (i = 0; i < size; ++i) {
> +        sam9->dbgu_regs[AT91_DBGU_RHR] = buf[i];
> +        sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_RXRDY;
> +        at91_dbgu_state_changed(sam9);
> +    }
> +}
> +
> +static void at91_dbgu_event(void *opaque, int event)
> +{
> +    DEBUG("begin\n");
> +}
> +
> +static uint32_t at91_bus_matrix_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("bus_matrix read offset %X\n", offset);
> +    return sam9->bus_matrix_regs[offset / 4];
> +}
> +
> +static void at91_bus_matrix_write(void *opaque, target_phys_addr_t offset,
> +                                  uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("bus_matrix write offset %X, value %X\n", offset, value);
> +    switch (offset) {
> +    case MATRIX_MRCR:
> +        DEBUG("write to MATRIX mrcr reg\n");
> +        if (value & (AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D)) {
> +            cpu_register_physical_memory(0x0, 80 * 1024, sam9->internal_sram | IO_MEM_RAM);
> +        }
> +        break;
> +    default:
> +        DEBUG("unimplemented\n");
> +        break;
> +    }
> +}
> +
> +static void at91_init_pmc(struct at91sam9_state *sam9)
> +{
> +    DEBUG("begin\n");
> +    sam9->pmc_regs[AT91_PMC_MCKR] = 0;
> +    sam9->pmc_regs[AT91_PMC_MOR] = 0;
> +    sam9->pmc_regs[AT91_PMC_SR] = 0x08;
> +    sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00;
> +    sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00;
> +}
> +
> +static void at91_init_bus_matrix(struct at91sam9_state *sam9)
> +{
> +    DEBUG("begin\n");
> +    memset(&sam9->bus_matrix_regs, 0, sizeof(sam9->bus_matrix_regs));
> +}
> +
> +static void at91_init_dbgu(struct at91sam9_state *sam9, CharDriverState *chr)
> +{
> +    DEBUG("begin\n");
> +
> +    memset(&sam9->dbgu_regs, 0, sizeof(sam9->dbgu_regs));
> +    sam9->dbgu_regs[AT91_DBGU_SR] = AT91_US_TXEMPTY | AT91_US_TXRDY;
> +
> +    sam9->dbgu.chr = chr;
> +    sam9->dbgu_tr_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *)dbgu_serial_end_xmit, sam9);
> +    sam9->char_transmit_time = (get_ticks_per_sec() / 115200) * 10;
> +    if (chr)
> +        qemu_chr_add_handlers(chr, at91_dbgu_can_receive,
> +                              at91_dbgu_receive,
> +                              at91_dbgu_event, sam9);
> +}
> +
> +static uint32_t at91_ccfg_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("ccfg read offset %X\n", offset);
> +    return sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])];
> +}
> +
> +static void at91_ccfg_write(void *opaque, target_phys_addr_t offset,
> +                            uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("ccfg write offset %X, value %X\n", offset, value);
> +    sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])] = value;
> +}
> +
> +static uint32_t at91_pio_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("pio read offset %X\n", offset);
> +    return sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])];
> +}
> +
> +static void at91_pio_write(void *opaque, target_phys_addr_t offset,
> +                           uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("pio write offset %X, value %X\n", offset, value);
> +    sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])] = value;
> +}
> +
> +static uint32_t at91_sdramc0_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("sdramc0 read offset %X\n", offset);
> +    return sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])];
> +}
> +
> +static void at91_sdramc0_write(void *opaque, target_phys_addr_t offset,
> +                               uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("sdramc0 write offset %X, value %X\n", offset, value);
> +    sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])] = value;
> +}
> +
> +static uint32_t at91_smc0_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("smc0 read offset %X\n", offset);
> +    return sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])];
> +}
> +
> +static void at91_smc0_write(void *opaque, target_phys_addr_t offset,
> +                            uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("smc0 write offset %X, value %X\n", offset, value);
> +    sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])] = value;
> +}
> +
> +static void at91_pitc_timer_tick(void * opaque)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    uint64_t val = ptimer_get_count(sam9->pitc_timer);
> +
> +    unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20) + 1;
> +    sam9->pitc_regs[AT91_PITC_PIIR] = (val & ((1 << 21) - 1)) | (tick << 20);
> +    sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR];
> +
> +    if ((sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITIEN) &&
> +        (sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) &&
> +        !sam9->pitc_regs[AT91_PITC_SR]) {
> +        sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID;
> +        sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID];
> +
> +        sam9->pitc_regs[AT91_PITC_SR] = 1;
> +        qemu_irq_raise(sam9->qirq[0]);
> +    }
> +}
> +
> +static uint32_t at91_pitc_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    int pitc_enable = !!(sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITEN);
> +    int idx;
> +
> +    idx = offset / sizeof(sam9->pitc_regs[0]);
> +    switch (idx) {
> +    case AT91_PITC_SR:
> +//        DEBUG("read sr: %X\n", sam9->pitc_regs[idx]);
> +        break;
> +    case AT91_PITC_PIVR:
> +        if (pitc_enable) {
> +//            DEBUG("clear sr\n");
> +            sam9->pitc_regs[AT91_PITC_SR] = 0;
> +        } else {
> +//            DEBUG("pitc disabled\n");
> +            break;
> +        }
> +    case AT91_PITC_PIIR:
> +        if (pitc_enable) {
> +            uint64_t val = ptimer_get_count(sam9->pitc_timer);
> +            unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20);
> +            uint32_t res = (tick << 20) | (val & ((1 << 21) - 1));
> +
> +            if (idx == AT91_PITC_PIVR)
> +                tick = 0;
> +            sam9->pitc_regs[AT91_PITC_PIIR] = (tick << 20) | (val & ((1 << 21) - 1));
> +            sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR];
> +            TRACE("pitc read offset %X, value %X\n", offset, res);
> +            return res;
> +        } else {
> +//            DEBUG("pitc disabled\n");
> +            break;
> +        }
> +
> +    default:
> +        /*nothing*/break;
> +    }
> +    TRACE("pitc read offset %X, value %X\n", offset, sam9->pitc_regs[idx]);
> +
> +    return sam9->pitc_regs[idx];
> +}
> +
> +static void at91_pitc_write(void *opaque, target_phys_addr_t offset,
> +                            uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +
> +    TRACE("pitc write offset %X, value %X\n", offset, value);
> +    int idx = offset / sizeof(sam9->pitc_regs[0]);
> +    switch (idx) {
> +    case AT91_PITC_MR: {
> +        int pitc_enable = !!(value & AT91_PTIC_MR_PITEN);
> +        unsigned int period = value & 0xFFFFF;
> +
> +        //DEBUG("set period %u, int enabled? %d\n", period, !!(value & AT91_PTIC_MR_PITIEN));
> +
> +        if (pitc_enable && period != 0) {
> +            sam9->timer_active = 1;
> +            //! \todo get real value from PLL
> +            ptimer_set_freq(sam9->pitc_timer, (100 * 1000 * 1000) / 16);
> +            ptimer_set_limit(sam9->pitc_timer, period, 1);
> +            ptimer_run(sam9->pitc_timer, 0);
> +        } else if (sam9->timer_active) {
> +            TRACE("disable timer\n");
> +            sam9->pitc_regs[AT91_PITC_PIVR] = 0;
> +            ptimer_stop(sam9->pitc_timer);
> +        }
> +    }
> +        break;
> +    default:
> +        TRACE("unhandled register %d\n", idx);
> +        break;
> +    }
> +    sam9->pitc_regs[idx] = value;
> +}
> +
> +static void at91_init_pitc(struct at91sam9_state *sam9)
> +{
> +    QEMUBH *bh;
> +
> +    DEBUG("begin\n");
> +    memset(&sam9->pitc_regs, 0, sizeof(sam9->pitc_regs));
> +    sam9->pitc_regs[AT91_PITC_MR] = 0xFFFFF;
> +    bh = qemu_bh_new(at91_pitc_timer_tick, sam9);
> +    sam9->pitc_timer = ptimer_init(bh);
> +}
> +
> +static uint32_t at91_aic_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    unsigned int idx = offset / sizeof(sam9->aic_regs[0]);
> +    if (idx == AT91_AIC_IVR) {
> +        qemu_irq_lower(sam9->qirq[0]);
> +    } else if (idx == AT91_AIC_ISR) {
> +        uint32_t val = sam9->aic_regs[idx];
> +        sam9->aic_regs[idx] = 0;
> +        return val;
> +    }
> +
> +    return sam9->aic_regs[idx];
> +}
> +
> +static void at91_aic_write(void *opaque, target_phys_addr_t offset,
> +                           uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    unsigned int idx = offset / sizeof(sam9->aic_regs[0]);
> +
> +    switch (idx) {
> +    case AT91_AIC_IECR:
> +        sam9->aic_regs[idx] |= value;
> +        break;
> +    case AT91_AIC_IDCR:
> +        sam9->aic_regs[idx] |= value;
> +        sam9->aic_regs[AT91_AIC_IECR] &= ~value;
> +        break;
> +    case AT91_AIC_IVR://ignore write
> +        break;
> +    case AT91_AIC_EOICR:
> +//        DEBUG("we write to end of interrupt reg\n");
> +        break;
> +    default:
> +        sam9->aic_regs[idx] = value;
> +        break;
> +    }
> +}
> +
> +static uint32_t at91_usart_read(void *opaque, target_phys_addr_t offset)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    DEBUG("we read from %X\n", offset);
> +    return sam9->usart0_regs[offset / sizeof(uint32_t)];
> +}
> +
> +static void at91_usart_write(void *opaque, target_phys_addr_t offset,
> +                             uint32_t value)
> +{
> +    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
> +    DEBUG("we write to %X: %X\n", offset, value);
> +    sam9->usart0_regs[offset / sizeof(uint32_t)] = value;
> +}
> +
> +
> +struct ip_block {
> +    target_phys_addr_t offset;
> +    target_phys_addr_t end_offset;
> +    uint32_t (*read_func)(void *, target_phys_addr_t);
> +    void (*write_func)(void *, target_phys_addr_t, uint32_t);
> +};
> +
> +static struct ip_block ip_blocks[] = {
> +    {AT91_USART0_BASE - AT91_PERIPH_BASE, AT91_USART0_BASE - AT91_PERIPH_BASE + 0x1000, at91_usart_read, at91_usart_write},
> +    {AT91_SDRAMC0_BASE - AT91_PERIPH_BASE, AT91_SMC0_BASE - AT91_PERIPH_BASE, at91_sdramc0_read, at91_sdramc0_write},
> +    {AT91_SMC0_BASE - AT91_PERIPH_BASE, AT91_ECC1_BASE - AT91_PERIPH_BASE, at91_smc0_read, at91_smc0_write},
> +    {AT91_BUS_MATRIX_BASE - AT91_PERIPH_BASE, AT91_CCFG_BASE - AT91_PERIPH_BASE, at91_bus_matrix_read, at91_bus_matrix_write},
> +    {AT91_CCFG_BASE - AT91_PERIPH_BASE, AT91_DBGU_BASE - AT91_PERIPH_BASE, at91_ccfg_read, at91_ccfg_write},
> +    {AT91_DBGU_BASE - AT91_PERIPH_BASE, AT91_AIC_BASE - AT91_PERIPH_BASE, at91_dbgu_read, at91_dbgu_write},
> +    {AT91_AIC_BASE - AT91_PERIPH_BASE, AT91_PIO_BASE - AT91_PERIPH_BASE, at91_aic_read, at91_aic_write},
> +    {AT91_PIO_BASE - AT91_PERIPH_BASE, AT91_PMC_BASE - AT91_PERIPH_BASE, at91_pio_read, at91_pio_write},
> +    {AT91_PMC_BASE - AT91_PERIPH_BASE, AT91_RSTC_BASE - AT91_PERIPH_BASE, at91_pmc_read, at91_pmc_write},
> +    {AT91_PITC_BASE - AT91_PERIPH_BASE, AT91_WDT_BASE - AT91_PERIPH_BASE, at91_pitc_read, at91_pitc_write},
> +};
> +
> +static uint32_t at91_periph_read(void *opaque, target_phys_addr_t offset)
> +{
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i)
> +        if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset)
> +            return ip_blocks[i].read_func(opaque, offset - ip_blocks[i].offset);
> +    DEBUG("read from unsupported periph addr %X\n", offset);
> +    return 0xFFFFFFFFUL;
> +}
> +
> +static void at91_periph_write(void *opaque, target_phys_addr_t offset,
> +                              uint32_t value)
> +{
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i)
> +        if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset) {
> +            ip_blocks[i].write_func(opaque, offset - ip_blocks[i].offset, value);
> +            return;
> +        }
> +    DEBUG("write to unsupported periph: addr %X, val %X\n", offset, value);
> +}
> +
> +/* Input 0 is IRQ and input 1 is FIQ.  */
> +static void arm_aic_cpu_handler(void *opaque, int irq, int level)
> +{
> +    CPUState *env = (CPUState *)opaque;
> +    switch (irq) {
> +    case ARM_AIC_CPU_IRQ:
> +        if (level)
> +            cpu_interrupt(env, CPU_INTERRUPT_HARD);
> +        else
> +            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
> +        break;
> +    case ARM_AIC_CPU_FIQ:
> +        if (level)
> +            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
> +        else
> +            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
> +        break;
> +    default:
> +        hw_error("arm_pic_cpu_handler: Bad interrput line %d\n", irq);
> +    }
> +}
> +
> +static void at91_aic_init(struct at91sam9_state *sam9)
> +{
> +    memset(&sam9->aic_regs[0], 0, sizeof(sam9->aic_regs));
> +    sam9->qirq = qemu_allocate_irqs(arm_aic_cpu_handler, sam9->env, 2);
> +}
> +
> +static CPUReadMemoryFunc *at91_periph_readfn[] = {
> +    at91_periph_read,
> +    at91_periph_read,
> +    at91_periph_read
> +};
> +
> +static CPUWriteMemoryFunc *at91_periph_writefn[] = {
> +    at91_periph_write,
> +    at91_periph_write,
> +    at91_periph_write
> +};
> +
> +
> +static void at91sam9_init(ram_addr_t ram_size,
> +                          const char *boot_device,
> +                          const char *kernel_filename,
> +                          const char *kernel_cmdline,
> +                          const char *initrd_filename,
> +                          const char *cpu_model)
> +{
> +    CPUState *env;
> +    DriveInfo *dinfo;
> +    struct at91sam9_state *sam9;
> +    int iomemtype;
> +
> +    DEBUG("begin, ram_size %llu\n", (unsigned long long)ram_size);
> +#ifdef TRACE_ON
> +    trace_file = fopen("/tmp/trace.log", "w");
> +#endif
> +    if (!cpu_model)
> +        cpu_model = "arm926";
> +    env = cpu_init(cpu_model);
> +    if (!env) {
> +        fprintf(stderr, "Unable to find CPU definition\n");
> +        exit(EXIT_FAILURE);
> +    }
> +    /* SDRAM at chipselect 1.  */
> +    cpu_register_physical_memory(AT91SAM9263EK_SDRAM_OFF, AT91SAM9263EK_SDRAM_SIZE,
> +                                 qemu_ram_alloc(AT91SAM9263EK_SDRAM_SIZE) | IO_MEM_RAM);
> +
> +    sam9 = (struct at91sam9_state *)qemu_mallocz(sizeof(*sam9));
> +    if (!sam9) {
> +        fprintf(stderr, "allocation failed\n");
> +        exit(EXIT_FAILURE);
> +    }
> +    sam9->env = env;
> +    /* Internal SRAM */
> +    sam9->internal_sram = qemu_ram_alloc(80 * 1024);
> +    cpu_register_physical_memory(0x00300000, 80 * 1024, sam9->internal_sram | IO_MEM_RAM);
> +
> +    /*Internal Peripherals */
> +    iomemtype = cpu_register_io_memory(at91_periph_readfn, at91_periph_writefn, sam9);
> +    cpu_register_physical_memory(0xF0000000, 0xFFFFFFFF - 0xF0000000, iomemtype);
> +
> +    at91_init_pmc(sam9);
> +    at91_init_bus_matrix(sam9);
> +    memset(&sam9->ccfg_regs, 0, sizeof(sam9->ccfg_regs));
> +    memset(&sam9->pio_regs, 0, sizeof(sam9->pio_regs));
> +    memset(&sam9->sdramc0_regs, 0, sizeof(sam9->sdramc0_regs));
> +    memset(&sam9->smc0_regs, 0, sizeof(sam9->smc0_regs));
> +    at91_init_dbgu(sam9, serial_hds[0]);
> +    at91_init_pitc(sam9);
> +    at91_aic_init(sam9);
> +    memset(sam9->usart0_regs, 0, sizeof(sam9->usart0_regs));
> +
> +    /*
> +      we use variant of booting from external memory (NOR FLASH),
> +      it mapped to 0x0 at start, and also it is accessable from 0x10000000 address
> +    */
> +    dinfo = drive_get(IF_PFLASH, 0, 0);
> +    if (dinfo) {
> +        ram_addr_t nor_flash_mem = qemu_ram_alloc(NOR_FLASH_SIZE);
> +        if (!nor_flash_mem) {
> +            fprintf(stderr, "allocation failed\n");
> +            exit(EXIT_FAILURE);
> +        }
> +
> +        sam9->norflash = pflash_cfi_atmel_register(AT91SAM9263EK_NORFLASH_OFF,
> +                                                   nor_flash_mem,
> +                                                   dinfo->bdrv,
> +                                                   4 * 1024 * 2, 8,
> +                                                   32 * 1024 * 2,
> +                                                   (135 - 8),
> +                                                   2, 0x001F, 0x01D6, 0, 0);
> +
> +        if (!sam9->norflash) {
> +            fprintf(stderr, "qemu: error registering flash memory.\n");
> +            exit(EXIT_FAILURE);
> +        }
> +
> +        DEBUG("register flash at 0x0\n");
> +        //register only part of flash, to prevent conflict with internal sram
> +        cpu_register_physical_memory(0x0, 100 * 1024 /*NOR_FLASH_SIZE*/,
> +                                     nor_flash_mem | IO_MEM_ROMD);
> +    } else {
> +        fprintf(stderr, "qemu: can not start without flash.\n");
> +        exit(EXIT_FAILURE);
> +    }
> +    env->regs[15] = 0x0;
> +}
> +
> +static QEMUMachine at91sam9263ek_machine = {
> +    .name = "at91sam9263ek",
> +    .desc = "Atmel at91sam9263ek board (ARM926EJ-S)",
> +    .init = at91sam9_init,
> +};
> +
> +static void at91sam9_machine_init(void)
> +{
> +    qemu_register_machine(&at91sam9263ek_machine);
> +}
> +
> +machine_init(at91sam9_machine_init)
> diff --git a/hw/at91sam9263_defs.h b/hw/at91sam9263_defs.h
> new file mode 100644
> index 0000000..c7136c3
> --- /dev/null
> +++ b/hw/at91sam9263_defs.h
> @@ -0,0 +1,144 @@
> +#ifndef _HW_AT91SAM9263_DEFS_H_
> +#define _HW_AT91SAM9263_DEFS_H_
> +
> +/* base periph addresses */
> +#define AT91_PERIPH_BASE     0xF0000000
> +#define AT91_USART0_BASE     0xFFF8C000
> +#define AT91_SDRAMC0_BASE    0xFFFFE200
> +#define AT91_SMC0_BASE       0xFFFFE400
> +#define AT91_ECC1_BASE       0xFFFFE600
> +#define AT91_BUS_MATRIX_BASE 0xFFFFEC00
> +#define AT91_CCFG_BASE       0xFFFFED10
> +#define AT91_DBGU_BASE       0xFFFFEE00
> +#define AT91_AIC_BASE        0xFFFFF000
> +#define AT91_PIO_BASE        0xFFFFF200
> +#define AT91_PMC_BASE        0xFFFFFC00
> +#define AT91_RSTC_BASE       0xFFFFFD00
> +#define AT91_PITC_BASE       0xFFFFFD30
> +#define AT91_WDT_BASE        0xFFFFFD40
> +
> +/* PMC registers */
> +#define AT91_PMC_SR (0x68 / sizeof(uint32_t))
> +#define AT91_PMC_MCKR (0x0020 / sizeof(uint32_t))
> +#define AT91_PMC_MOR (0x30 / sizeof(uint32_t))
> +#define AT91_PMC_CSS             (0x3 <<  0) // (PMC) Programmable Clock Selection
> +#define AT91_PMC_MCKRDY          (0x1 <<  3) // (PMC) Master Clock Status/Enable/Disable/Mask
> +#define AT91_PMC_MOSCS           (0x1 <<  0) // (PMC) MOSC Status/Enable/Disable/Mask
> +#define AT91_CKGR_MOSCEN         (0x1 <<  0) // (CKGR) Main Oscillator Enable
> +#define AT91_PMC_PLLAR (0x0028 / sizeof(uint32_t))
> +#define AT91_PMC_PLLBR (0x002C / sizeof(uint32_t))
> +#define AT91_PMC_LOCKA           (0x1 <<  1) // (PMC) PLL A Status/Enable/Disable/Mask
> +#define AT91_PMC_LOCKB           (0x1 <<  2) // (PMC) PLL B Status/Enable/Disable/Mask
> +#define AT91_PMC_PCER (0x10 / sizeof(uint32_t))
> +
> +/*dbgu registers */
> +#define AT91_DBGU_CR   0x0
> +#define AT91_DBGU_MR   (4 / sizeof(uint32_t))
> +#define AT91_DBGU_IER  (8 / sizeof(uint32_t))
> +#define AT91_DBGU_IDR  (0xC / sizeof(uint32_t))
> +#define AT91_DBGU_IMR  (0x10 / sizeof(uint32_t))
> +#define AT91_DBGU_SR   (0x14 / sizeof(uint32_t))
> +#define AT91_DBGU_RHR  (0x18 / sizeof(uint32_t))
> +#define AT91_DBGU_THR  (0x001C / sizeof(uint32_t))
> +#define AT91_DBGU_BRGR (0x0020 / sizeof(uint32_t))
> +
> +
> +// -------- DBGU_CR : (DBGU Offset: 0x0) Debug Unit Control Register --------
> +#define AT91_US_RSTRX            (0x1 <<  2) // (DBGU) Reset Receiver
> +#define AT91_US_RSTTX            (0x1 <<  3) // (DBGU) Reset Transmitter
> +#define AT91_US_RXEN             (0x1 <<  4) // (DBGU) Receiver Enable
> +#define AT91_US_RXDIS            (0x1 <<  5) // (DBGU) Receiver Disable
> +#define AT91_US_TXEN             (0x1 <<  6) // (DBGU) Transmitter Enable
> +#define AT91_US_TXDIS            (0x1 <<  7) // (DBGU) Transmitter Disable
> +#define AT91_US_RSTSTA           (0x1 <<  8) // (DBGU) Reset Status Bits
> +// -------- DBGU_IER : (DBGU Offset: 0x8) Debug Unit Interrupt Enable Register --------
> +#define AT91_US_RXRDY            (0x1 <<  0) // (DBGU) RXRDY Interrupt
> +#define AT91_US_TXRDY            (0x1 <<  1) // (DBGU) TXRDY Interrupt
> +#define AT91_US_ENDRX            (0x1 <<  3) // (DBGU) End of Receive Transfer Interrupt
> +#define AT91_US_ENDTX            (0x1 <<  4) // (DBGU) End of Transmit Interrupt
> +#define AT91_US_OVRE             (0x1 <<  5) // (DBGU) Overrun Interrupt
> +#define AT91_US_FRAME            (0x1 <<  6) // (DBGU) Framing Error Interrupt
> +#define AT91_US_PARE             (0x1 <<  7) // (DBGU) Parity Error Interrupt
> +#define AT91_US_TXEMPTY          (0x1 <<  9) // (DBGU) TXEMPTY Interrupt
> +#define AT91_US_TXBUFE           (0x1 << 11) // (DBGU) TXBUFE Interrupt
> +#define AT91_US_RXBUFF           (0x1 << 12) // (DBGU) RXBUFF Interrupt
> +#define AT91_US_COMM_TX          (0x1 << 30) // (DBGU) COMM_TX Interrupt
> +#define AT91_US_COMM_RX          (0x1 << 31) // (DBGU) COMM_RX Interrupt
> +
> +/* US registers */
> +#define AT91_US_CR  (0)
> +#define AT91_US_MR  (4 / sizeof(uint32_t))
> +#define AT91_US_IER (8 / sizeof(uint32_t))
> +#define AT91_US_IDR (0xC / sizeof(uint32_t))
> +#define AT91_US_IMR (0x10 / sizeof(uint32_t))
> +
> +/* matrix */
> +
> +// *****************************************************************************
> +//              SOFTWARE API DEFINITION  FOR AHB Matrix Interface
> +// *****************************************************************************
> +// *** Register offset in AT91S_MATRIX structure ***
> +#define MATRIX_MCFG0    ( 0) //  Master Configuration Register 0
> +#define MATRIX_MCFG1    ( 4) //  Master Configuration Register 1
> +#define MATRIX_MCFG2    ( 8) //  Master Configuration Register 2
> +#define MATRIX_MCFG3    (12) //  Master Configuration Register 3
> +#define MATRIX_MCFG4    (16) //  Master Configuration Register 4
> +#define MATRIX_MCFG5    (20) //  Master Configuration Register 5
> +#define MATRIX_MCFG6    (24) //  Master Configuration Register 6
> +#define MATRIX_MCFG7    (28) //  Master Configuration Register 7
> +#define MATRIX_MCFG8    (32) //  Master Configuration Register 8
> +#define MATRIX_SCFG0    (64) //  Slave Configuration Register 0
> +#define MATRIX_SCFG1    (68) //  Slave Configuration Register 1
> +#define MATRIX_SCFG2    (72) //  Slave Configuration Register 2
> +#define MATRIX_SCFG3    (76) //  Slave Configuration Register 3
> +#define MATRIX_SCFG4    (80) //  Slave Configuration Register 4
> +#define MATRIX_SCFG5    (84) //  Slave Configuration Register 5
> +#define MATRIX_SCFG6    (88) //  Slave Configuration Register 6
> +#define MATRIX_SCFG7    (92) //  Slave Configuration Register 7
> +#define MATRIX_PRAS0    (128) //  PRAS0
> +#define MATRIX_PRBS0    (132) //  PRBS0
> +#define MATRIX_PRAS1    (136) //  PRAS1
> +#define MATRIX_PRBS1    (140) //  PRBS1
> +#define MATRIX_PRAS2    (144) //  PRAS2
> +#define MATRIX_PRBS2    (148) //  PRBS2
> +#define MATRIX_PRAS3    (152) //  PRAS3
> +#define MATRIX_PRBS3    (156) //  PRBS3
> +#define MATRIX_PRAS4    (160) //  PRAS4
> +#define MATRIX_PRBS4    (164) //  PRBS4
> +#define MATRIX_PRAS5    (168) //  PRAS5
> +#define MATRIX_PRBS5    (172) //  PRBS5
> +#define MATRIX_PRAS6    (176) //  PRAS6
> +#define MATRIX_PRBS6    (180) //  PRBS6
> +#define MATRIX_PRAS7    (184) //  PRAS7
> +#define MATRIX_PRBS7    (188) //  PRBS7
> +#define MATRIX_MRCR     (256) //  Master Remp Control Register
> +
> +#define AT91C_MATRIX_RCA926I      (0x1 <<  0) // (MATRIX) Remap Command Bit for ARM926EJ-S Instruction
> +#define AT91C_MATRIX_RCA926D      (0x1 <<  1) // (MATRIX) Remap Command Bit for ARM926EJ-S Data
> +#define AT91C_MATRIX_RCB2         (0x1 <<  2) // (MATRIX) Remap Command Bit for PDC
> +#define AT91C_MATRIX_RCB3         (0x1 <<  3) // (MATRIX) Remap Command Bit for LCD
> +#define AT91C_MATRIX_RCB4         (0x1 <<  4) // (MATRIX) Remap Command Bit for 2DGC
> +#define AT91C_MATRIX_RCB5         (0x1 <<  5) // (MATRIX) Remap Command Bit for ISI
> +#define AT91C_MATRIX_RCB6         (0x1 <<  6) // (MATRIX) Remap Command Bit for DMA
> +#define AT91C_MATRIX_RCB7         (0x1 <<  7) // (MATRIX) Remap Command Bit for EMAC
> +#define AT91C_MATRIX_RCB8         (0x1 <<  8) // (MATRIX) Remap Command Bit for USB
> +
> +/*pitc */
> +#define AT91_PTIC_MR_PITEN  (1 << 24)
> +#define AT91_PTIC_MR_PITIEN (1 << 25)
> +#define AT91_PITC_MR      0
> +#define AT91_PITC_SR   (0x4 / sizeof(uint32_t))
> +#define AT91_PITC_PIVR (0x8 / sizeof(uint32_t))
> +#define AT91_PITC_PIIR (0xC / sizeof(uint32_t))
> +
> +/*AIC registers*/
> +#define AT91_AIC_SVR0  (0x80  / sizeof(uint32_t))
> +#define AT91_AIC_ISR   (0x108 / sizeof(uint32_t))
> +#define AT91_AIC_IECR  (0x120 / sizeof(uint32_t))
> +#define AT91_AIC_EOICR (0x130 / sizeof(uint32_t))
> +#define AT91_AIC_IVR   (0x100 / sizeof(uint32_t))
> +#define AT91_AIC_IDCR  (0x124 / sizeof(uint32_t))
> +
> +#define AT91_PERIPH_SYS_ID 1
> +
> +#endif//!_HW_AT91SAM9263_DEFS_H_
> --
> 1.6.5.2
>
> --
> /Evgeniy
>
>
>
>
Evgeniy Dushistov Nov. 17, 2009, 7:23 p.m. UTC | #2
On Tue, Nov 17, 2009 at 10:39:27AM +0100, Filip Navara wrote:
> I'd say it is preferable to split the individual devices and model
> them using the QDEV infrastructure instead of putting it all together
> into one "system controller" device.
> 
> I've QDEV-based implementation of these devices already: PMC, DBGU,
> PIO, PITC, AIC. That leaves the "bus matrix", SDRAM controller and
> USART (which is very similar to DBGU) to be split up.
> 

I also see ethernet IP block (emac), 
I have plans to implement it,
what about USB slave and CAN controller, you plan/have implementations
of them?
Filip Navara Nov. 17, 2009, 11:43 p.m. UTC | #3
On Tue, Nov 17, 2009 at 8:23 PM, Evgeniy Dushistov <dushistov@mail.ru> wrote:
> On Tue, Nov 17, 2009 at 10:39:27AM +0100, Filip Navara wrote:
>> I'd say it is preferable to split the individual devices and model
>> them using the QDEV infrastructure instead of putting it all together
>> into one "system controller" device.
>>
>> I've QDEV-based implementation of these devices already: PMC, DBGU,
>> PIO, PITC, AIC. That leaves the "bus matrix", SDRAM controller and
>> USART (which is very similar to DBGU) to be split up.
>>
>
> I also see ethernet IP block (emac),
> I have plans to implement it,
> what about USB slave and CAN controller, you plan/have implementations
> of them?

The EMAC emulation is fully functional and good enough to run a
FreeRTOS/uIP web server and all Atmel examples. I do not plan to
implement USB slave or CAN controller, but I would certainly welcome
if you (or someone else) implemented it. If anything then I will
implement I2C.

Best regards,
Filip Navara
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index 7542199..67f441d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -268,7 +268,7 @@  obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
 endif
 
 obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o
-obj-arm-y += pflash_atmel.o
+obj-arm-y += pflash_atmel.o at91sam9.o
 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o
diff --git a/hw/at91sam9.c b/hw/at91sam9.c
new file mode 100644
index 0000000..7ac60d9
--- /dev/null
+++ b/hw/at91sam9.c
@@ -0,0 +1,695 @@ 
+/*
+ * Atmel at91sam9263 cpu + NOR flash + SDRAM emulation
+ * Written by Evgeniy Dushistov
+ * This code is licenced under the GPL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "hw.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "net.h"
+#include "sysemu.h"
+#include "flash.h"
+#include "boards.h"
+#include "qemu-char.h"
+#include "qemu-timer.h"
+
+#include "at91sam9263_defs.h"
+
+//#define AT91_TRACE_ON
+//#define AT91_DEBUG_ON
+
+#define ARM_AIC_CPU_IRQ 0
+#define ARM_AIC_CPU_FIQ 1
+
+#define NOR_FLASH_SIZE (1024 * 1024 * 8)
+#define AT91SAM9263EK_SDRAM_SIZE (1024 * 1024 * 64)
+#define AT91SAM9263EK_SDRAM_OFF 0x20000000
+#define AT91SAM9263EK_NORFLASH_OFF 0x10000000
+
+#ifdef AT91_DEBUG_ON
+#       define DEBUG(f, a...)    {              \
+        printf ("at91 (%s, %d): %s:",           \
+                __FILE__, __LINE__, __func__);  \
+        printf (f, ## a);                       \
+    }
+#else
+#       define DEBUG(f, a...) do { } while (0)
+#endif
+
+#ifdef AT91_TRACE_ON
+static FILE *trace_file;
+#       define TRACE(f, a...)    do {           \
+        fprintf (trace_file, f, ## a);          \
+    } while (0)
+#else
+#       define TRACE(f, a...) do { } while (0)
+#endif
+
+
+struct dbgu_state {
+    CharDriverState *chr;
+};
+
+struct at91sam9_state {
+    uint32_t pmc_regs[28];
+    uint32_t dbgu_regs[0x124 / 4];
+    uint32_t bus_matrix_regs[0x100 / 4];
+    uint32_t ccfg_regs[(0x01FC - 0x0110 + 1) / sizeof(uint32_t)];
+    uint32_t pio_regs[(AT91_PMC_BASE - AT91_PIO_BASE) / sizeof(uint32_t)];
+    uint32_t sdramc0_regs[(AT91_SMC0_BASE - AT91_SDRAMC0_BASE) / sizeof(uint32_t)];
+    uint32_t smc0_regs[(AT91_ECC1_BASE - AT91_SMC0_BASE) / sizeof(uint32_t)];
+    uint32_t pitc_regs[80];
+    uint32_t aic_regs[(AT91_PIO_BASE - AT91_AIC_BASE) / sizeof(uint32_t)];
+    uint32_t usart0_regs[0x1000 / sizeof(uint32_t)];
+    struct dbgu_state dbgu;
+    pflash_t *norflash;
+    ram_addr_t internal_sram;
+    QEMUTimer *dbgu_tr_timer;
+    ptimer_state *pitc_timer;
+    int timer_active;
+    CPUState *env;
+    qemu_irq *qirq;
+    uint64_t char_transmit_time;
+};
+
+static uint32_t at91_pmc_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    TRACE("pmc read offset %X\n", offset);
+    return sam9->pmc_regs[offset / 4];
+}
+
+static void at91_pmc_write(void *opaque, target_phys_addr_t offset,
+                           uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("pmc write offset %X, value %X\n", offset, value);
+    switch (offset / 4) {
+    case AT91_PMC_MCKR:
+        sam9->pmc_regs[AT91_PMC_MCKR] = value;
+        switch (value & AT91_PMC_CSS) {
+        case 1:
+            //Main clock is selected
+            sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MCKRDY | AT91_PMC_MOSCS;
+            break;
+        default:
+            DEBUG("unimplemented\n");
+            break;
+        }
+        break;
+    case AT91_PMC_MOR:
+        sam9->pmc_regs[AT91_PMC_MOR] = value;
+        if (value & 1) {
+            sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_MOSCS;
+        }
+        break;
+    case AT91_PMC_PLLAR:
+        sam9->pmc_regs[AT91_PMC_PLLAR] = value;
+        sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKA;
+        break;
+    case AT91_PMC_PLLBR:
+        sam9->pmc_regs[AT91_PMC_PLLBR] = value;
+        sam9->pmc_regs[AT91_PMC_SR] |= AT91_PMC_LOCKB;
+        break;
+    case AT91_PMC_PCER:
+        sam9->pmc_regs[AT91_PMC_PCER] |= value;
+        break;
+    default:
+        //DEBUG("unimplemented, offset %X\n", offset);
+        break;
+    }
+}
+
+static uint32_t at91_dbgu_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    offset /= 4;
+    if (offset == AT91_DBGU_RHR) {
+        sam9->dbgu_regs[AT91_DBGU_SR] &= (uint32_t)~1;
+    }/* else if (offset == AT91_DBGU_SR)*/
+
+    return sam9->dbgu_regs[offset];
+}
+
+static void at91_dbgu_state_changed(struct at91sam9_state *sam9)
+{
+    if ((sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) &&
+        (sam9->dbgu_regs[AT91_DBGU_IMR] & sam9->dbgu_regs[AT91_DBGU_SR])) {
+        sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID;
+        sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID];
+        qemu_irq_raise(sam9->qirq[0]);
+    }
+}
+
+static void dbgu_serial_end_xmit(void *opaque)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    sam9->dbgu_regs[AT91_DBGU_SR] |= (AT91_US_TXEMPTY | AT91_US_TXRDY);
+    at91_dbgu_state_changed(sam9);
+}
+
+static void at91_dbgu_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    unsigned char ch;
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    switch (offset / 4) {
+    case AT91_DBGU_CR:
+        sam9->dbgu_regs[AT91_DBGU_CR] = value;
+        if (value & AT91_US_TXEN)
+            sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_TXRDY | AT91_US_TXEMPTY;
+        if (value & AT91_US_TXDIS)
+            sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXRDY | AT91_US_TXEMPTY);
+        break;
+    case AT91_DBGU_IER:
+        sam9->dbgu_regs[AT91_DBGU_IMR] |= value;
+        at91_dbgu_state_changed(sam9);
+        break;
+    case AT91_DBGU_IDR:
+        sam9->dbgu_regs[AT91_DBGU_IMR] &= ~value;
+        break;
+    case AT91_DBGU_THR:
+        sam9->dbgu_regs[AT91_DBGU_THR] = value;
+        sam9->dbgu_regs[AT91_DBGU_SR] &= ~(AT91_US_TXEMPTY | AT91_US_TXRDY);
+        ch = value;
+        if (sam9->dbgu.chr)
+            qemu_chr_write(sam9->dbgu.chr, &ch, 1);
+        qemu_mod_timer(sam9->dbgu_tr_timer , qemu_get_clock(vm_clock) + sam9->char_transmit_time);
+        break;
+    default:
+        //DEBUG("unimplemented\n");
+        break;
+    }
+}
+
+static int at91_dbgu_can_receive(void *opaque)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    return (sam9->dbgu_regs[AT91_DBGU_SR] & AT91_US_RXRDY) == 0;
+}
+
+static void at91_dbgu_receive(void *opaque, const uint8_t *buf, int size)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    int i;
+    /*! \todo if not one character we need wait before irq handled,
+      but from other hand at91_dbgu_can_receive should prevent this
+     */
+    for (i = 0; i < size; ++i) {
+        sam9->dbgu_regs[AT91_DBGU_RHR] = buf[i];
+        sam9->dbgu_regs[AT91_DBGU_SR] |= AT91_US_RXRDY;
+        at91_dbgu_state_changed(sam9);
+    }
+}
+
+static void at91_dbgu_event(void *opaque, int event)
+{
+    DEBUG("begin\n");
+}
+
+static uint32_t at91_bus_matrix_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("bus_matrix read offset %X\n", offset);
+    return sam9->bus_matrix_regs[offset / 4];
+}
+
+static void at91_bus_matrix_write(void *opaque, target_phys_addr_t offset,
+                                  uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("bus_matrix write offset %X, value %X\n", offset, value);
+    switch (offset) {
+    case MATRIX_MRCR:
+        DEBUG("write to MATRIX mrcr reg\n");
+        if (value & (AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D)) {
+            cpu_register_physical_memory(0x0, 80 * 1024, sam9->internal_sram | IO_MEM_RAM);
+        }
+        break;
+    default:
+        DEBUG("unimplemented\n");
+        break;
+    }
+}
+
+static void at91_init_pmc(struct at91sam9_state *sam9)
+{
+    DEBUG("begin\n");
+    sam9->pmc_regs[AT91_PMC_MCKR] = 0;
+    sam9->pmc_regs[AT91_PMC_MOR] = 0;
+    sam9->pmc_regs[AT91_PMC_SR] = 0x08;
+    sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00;
+    sam9->pmc_regs[AT91_PMC_PLLAR] = 0x3F00;
+}
+
+static void at91_init_bus_matrix(struct at91sam9_state *sam9)
+{
+    DEBUG("begin\n");
+    memset(&sam9->bus_matrix_regs, 0, sizeof(sam9->bus_matrix_regs));
+}
+
+static void at91_init_dbgu(struct at91sam9_state *sam9, CharDriverState *chr)
+{
+    DEBUG("begin\n");
+
+    memset(&sam9->dbgu_regs, 0, sizeof(sam9->dbgu_regs));
+    sam9->dbgu_regs[AT91_DBGU_SR] = AT91_US_TXEMPTY | AT91_US_TXRDY;
+
+    sam9->dbgu.chr = chr;
+    sam9->dbgu_tr_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *)dbgu_serial_end_xmit, sam9);
+    sam9->char_transmit_time = (get_ticks_per_sec() / 115200) * 10;
+    if (chr)
+        qemu_chr_add_handlers(chr, at91_dbgu_can_receive,
+                              at91_dbgu_receive,
+                              at91_dbgu_event, sam9);
+}
+
+static uint32_t at91_ccfg_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("ccfg read offset %X\n", offset);
+    return sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])];
+}
+
+static void at91_ccfg_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("ccfg write offset %X, value %X\n", offset, value);
+    sam9->ccfg_regs[offset / sizeof(sam9->ccfg_regs[0])] = value;
+}
+
+static uint32_t at91_pio_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("pio read offset %X\n", offset);
+    return sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])];
+}
+
+static void at91_pio_write(void *opaque, target_phys_addr_t offset,
+                           uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("pio write offset %X, value %X\n", offset, value);
+    sam9->pio_regs[offset / sizeof(sam9->pio_regs[0])] = value;
+}
+
+static uint32_t at91_sdramc0_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+ 
+    TRACE("sdramc0 read offset %X\n", offset);
+    return sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])];
+}
+
+static void at91_sdramc0_write(void *opaque, target_phys_addr_t offset,
+                               uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+ 
+    TRACE("sdramc0 write offset %X, value %X\n", offset, value);
+    sam9->sdramc0_regs[offset / sizeof(sam9->sdramc0_regs[0])] = value;
+}
+
+static uint32_t at91_smc0_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("smc0 read offset %X\n", offset);
+    return sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])];
+}
+
+static void at91_smc0_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("smc0 write offset %X, value %X\n", offset, value);
+    sam9->smc0_regs[offset / sizeof(sam9->smc0_regs[0])] = value;
+}
+
+static void at91_pitc_timer_tick(void * opaque)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    uint64_t val = ptimer_get_count(sam9->pitc_timer);
+
+    unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20) + 1;
+    sam9->pitc_regs[AT91_PITC_PIIR] = (val & ((1 << 21) - 1)) | (tick << 20);
+    sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR];
+
+    if ((sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITIEN) &&
+        (sam9->aic_regs[AT91_AIC_IECR] & (1 << AT91_PERIPH_SYS_ID)) &&
+        !sam9->pitc_regs[AT91_PITC_SR]) {
+        sam9->aic_regs[AT91_AIC_ISR] = AT91_PERIPH_SYS_ID;
+        sam9->aic_regs[AT91_AIC_IVR] = sam9->aic_regs[AT91_AIC_SVR0 + AT91_PERIPH_SYS_ID];
+
+        sam9->pitc_regs[AT91_PITC_SR] = 1;
+        qemu_irq_raise(sam9->qirq[0]);
+    }
+}
+
+static uint32_t at91_pitc_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    int pitc_enable = !!(sam9->pitc_regs[AT91_PITC_MR] & AT91_PTIC_MR_PITEN);
+    int idx;
+
+    idx = offset / sizeof(sam9->pitc_regs[0]);
+    switch (idx) {
+    case AT91_PITC_SR:
+//        DEBUG("read sr: %X\n", sam9->pitc_regs[idx]);
+        break;
+    case AT91_PITC_PIVR:
+        if (pitc_enable) {
+//            DEBUG("clear sr\n");
+            sam9->pitc_regs[AT91_PITC_SR] = 0;
+        } else {
+//            DEBUG("pitc disabled\n");
+            break;
+        }
+    case AT91_PITC_PIIR:
+        if (pitc_enable) {
+            uint64_t val = ptimer_get_count(sam9->pitc_timer);
+            unsigned int tick = (sam9->pitc_regs[AT91_PITC_PIIR] >> 20);
+            uint32_t res = (tick << 20) | (val & ((1 << 21) - 1));
+
+            if (idx == AT91_PITC_PIVR)
+                tick = 0;
+            sam9->pitc_regs[AT91_PITC_PIIR] = (tick << 20) | (val & ((1 << 21) - 1));
+            sam9->pitc_regs[AT91_PITC_PIVR] = sam9->pitc_regs[AT91_PITC_PIIR];
+            TRACE("pitc read offset %X, value %X\n", offset, res);
+            return res;
+        } else {
+//            DEBUG("pitc disabled\n");
+            break;
+        }
+
+    default:
+        /*nothing*/break;
+    }
+    TRACE("pitc read offset %X, value %X\n", offset, sam9->pitc_regs[idx]);
+
+    return sam9->pitc_regs[idx];
+}
+
+static void at91_pitc_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+
+    TRACE("pitc write offset %X, value %X\n", offset, value);
+    int idx = offset / sizeof(sam9->pitc_regs[0]);
+    switch (idx) {
+    case AT91_PITC_MR: {
+        int pitc_enable = !!(value & AT91_PTIC_MR_PITEN);
+        unsigned int period = value & 0xFFFFF;
+
+        //DEBUG("set period %u, int enabled? %d\n", period, !!(value & AT91_PTIC_MR_PITIEN));
+
+        if (pitc_enable && period != 0) {
+            sam9->timer_active = 1;
+            //! \todo get real value from PLL
+            ptimer_set_freq(sam9->pitc_timer, (100 * 1000 * 1000) / 16);
+            ptimer_set_limit(sam9->pitc_timer, period, 1);
+            ptimer_run(sam9->pitc_timer, 0);
+        } else if (sam9->timer_active) {
+            TRACE("disable timer\n");
+            sam9->pitc_regs[AT91_PITC_PIVR] = 0;
+            ptimer_stop(sam9->pitc_timer);
+        }
+    }
+        break;
+    default:
+        TRACE("unhandled register %d\n", idx);
+        break;
+    }
+    sam9->pitc_regs[idx] = value;
+}
+
+static void at91_init_pitc(struct at91sam9_state *sam9)
+{
+    QEMUBH *bh;
+
+    DEBUG("begin\n");
+    memset(&sam9->pitc_regs, 0, sizeof(sam9->pitc_regs));
+    sam9->pitc_regs[AT91_PITC_MR] = 0xFFFFF;
+    bh = qemu_bh_new(at91_pitc_timer_tick, sam9);
+    sam9->pitc_timer = ptimer_init(bh);
+}
+
+static uint32_t at91_aic_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    unsigned int idx = offset / sizeof(sam9->aic_regs[0]);
+    if (idx == AT91_AIC_IVR) {
+        qemu_irq_lower(sam9->qirq[0]);
+    } else if (idx == AT91_AIC_ISR) {
+        uint32_t val = sam9->aic_regs[idx];
+        sam9->aic_regs[idx] = 0;
+        return val;
+    }
+
+    return sam9->aic_regs[idx];
+}
+
+static void at91_aic_write(void *opaque, target_phys_addr_t offset,
+                           uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    unsigned int idx = offset / sizeof(sam9->aic_regs[0]);
+
+    switch (idx) {
+    case AT91_AIC_IECR:
+        sam9->aic_regs[idx] |= value;
+        break;
+    case AT91_AIC_IDCR:
+        sam9->aic_regs[idx] |= value;
+        sam9->aic_regs[AT91_AIC_IECR] &= ~value;
+        break;
+    case AT91_AIC_IVR://ignore write
+        break;
+    case AT91_AIC_EOICR:
+//        DEBUG("we write to end of interrupt reg\n");
+        break;
+    default:
+        sam9->aic_regs[idx] = value;
+        break;
+    }
+}
+
+static uint32_t at91_usart_read(void *opaque, target_phys_addr_t offset)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    DEBUG("we read from %X\n", offset);
+    return sam9->usart0_regs[offset / sizeof(uint32_t)];
+}
+
+static void at91_usart_write(void *opaque, target_phys_addr_t offset,
+                             uint32_t value)
+{
+    struct at91sam9_state *sam9 = (struct at91sam9_state *)opaque;
+    DEBUG("we write to %X: %X\n", offset, value);
+    sam9->usart0_regs[offset / sizeof(uint32_t)] = value;
+}
+
+
+struct ip_block {
+    target_phys_addr_t offset;
+    target_phys_addr_t end_offset;
+    uint32_t (*read_func)(void *, target_phys_addr_t);
+    void (*write_func)(void *, target_phys_addr_t, uint32_t);
+};
+
+static struct ip_block ip_blocks[] = {
+    {AT91_USART0_BASE - AT91_PERIPH_BASE, AT91_USART0_BASE - AT91_PERIPH_BASE + 0x1000, at91_usart_read, at91_usart_write},
+    {AT91_SDRAMC0_BASE - AT91_PERIPH_BASE, AT91_SMC0_BASE - AT91_PERIPH_BASE, at91_sdramc0_read, at91_sdramc0_write},
+    {AT91_SMC0_BASE - AT91_PERIPH_BASE, AT91_ECC1_BASE - AT91_PERIPH_BASE, at91_smc0_read, at91_smc0_write},
+    {AT91_BUS_MATRIX_BASE - AT91_PERIPH_BASE, AT91_CCFG_BASE - AT91_PERIPH_BASE, at91_bus_matrix_read, at91_bus_matrix_write},
+    {AT91_CCFG_BASE - AT91_PERIPH_BASE, AT91_DBGU_BASE - AT91_PERIPH_BASE, at91_ccfg_read, at91_ccfg_write},
+    {AT91_DBGU_BASE - AT91_PERIPH_BASE, AT91_AIC_BASE - AT91_PERIPH_BASE, at91_dbgu_read, at91_dbgu_write},
+    {AT91_AIC_BASE - AT91_PERIPH_BASE, AT91_PIO_BASE - AT91_PERIPH_BASE, at91_aic_read, at91_aic_write},
+    {AT91_PIO_BASE - AT91_PERIPH_BASE, AT91_PMC_BASE - AT91_PERIPH_BASE, at91_pio_read, at91_pio_write},
+    {AT91_PMC_BASE - AT91_PERIPH_BASE, AT91_RSTC_BASE - AT91_PERIPH_BASE, at91_pmc_read, at91_pmc_write},
+    {AT91_PITC_BASE - AT91_PERIPH_BASE, AT91_WDT_BASE - AT91_PERIPH_BASE, at91_pitc_read, at91_pitc_write},
+};
+
+static uint32_t at91_periph_read(void *opaque, target_phys_addr_t offset)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i)
+        if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset)
+            return ip_blocks[i].read_func(opaque, offset - ip_blocks[i].offset);
+    DEBUG("read from unsupported periph addr %X\n", offset);
+    return 0xFFFFFFFFUL;
+}
+
+static void at91_periph_write(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ip_blocks); ++i)
+        if (offset >= ip_blocks[i].offset && offset < ip_blocks[i].end_offset) {
+            ip_blocks[i].write_func(opaque, offset - ip_blocks[i].offset, value);
+            return;
+        }
+    DEBUG("write to unsupported periph: addr %X, val %X\n", offset, value);
+}
+
+/* Input 0 is IRQ and input 1 is FIQ.  */
+static void arm_aic_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = (CPUState *)opaque;
+    switch (irq) {
+    case ARM_AIC_CPU_IRQ:
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        break;
+    case ARM_AIC_CPU_FIQ:
+        if (level)
+            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
+        else
+            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
+        break;
+    default:
+        hw_error("arm_pic_cpu_handler: Bad interrput line %d\n", irq);
+    }
+}
+
+static void at91_aic_init(struct at91sam9_state *sam9)
+{
+    memset(&sam9->aic_regs[0], 0, sizeof(sam9->aic_regs));
+    sam9->qirq = qemu_allocate_irqs(arm_aic_cpu_handler, sam9->env, 2);
+}
+
+static CPUReadMemoryFunc *at91_periph_readfn[] = {
+    at91_periph_read,
+    at91_periph_read,
+    at91_periph_read
+};
+
+static CPUWriteMemoryFunc *at91_periph_writefn[] = {
+    at91_periph_write,
+    at91_periph_write,
+    at91_periph_write
+};
+
+
+static void at91sam9_init(ram_addr_t ram_size,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename,
+                          const char *cpu_model)
+{
+    CPUState *env;
+    DriveInfo *dinfo;
+    struct at91sam9_state *sam9;
+    int iomemtype;
+
+    DEBUG("begin, ram_size %llu\n", (unsigned long long)ram_size);
+#ifdef TRACE_ON
+    trace_file = fopen("/tmp/trace.log", "w");
+#endif
+    if (!cpu_model)
+        cpu_model = "arm926";
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(EXIT_FAILURE);
+    }
+    /* SDRAM at chipselect 1.  */
+    cpu_register_physical_memory(AT91SAM9263EK_SDRAM_OFF, AT91SAM9263EK_SDRAM_SIZE,
+                                 qemu_ram_alloc(AT91SAM9263EK_SDRAM_SIZE) | IO_MEM_RAM);
+
+    sam9 = (struct at91sam9_state *)qemu_mallocz(sizeof(*sam9));
+    if (!sam9) {
+        fprintf(stderr, "allocation failed\n");
+        exit(EXIT_FAILURE);
+    }
+    sam9->env = env;
+    /* Internal SRAM */
+    sam9->internal_sram = qemu_ram_alloc(80 * 1024);
+    cpu_register_physical_memory(0x00300000, 80 * 1024, sam9->internal_sram | IO_MEM_RAM);
+
+    /*Internal Peripherals */
+    iomemtype = cpu_register_io_memory(at91_periph_readfn, at91_periph_writefn, sam9);
+    cpu_register_physical_memory(0xF0000000, 0xFFFFFFFF - 0xF0000000, iomemtype);
+
+    at91_init_pmc(sam9);
+    at91_init_bus_matrix(sam9);
+    memset(&sam9->ccfg_regs, 0, sizeof(sam9->ccfg_regs));
+    memset(&sam9->pio_regs, 0, sizeof(sam9->pio_regs));
+    memset(&sam9->sdramc0_regs, 0, sizeof(sam9->sdramc0_regs));
+    memset(&sam9->smc0_regs, 0, sizeof(sam9->smc0_regs));
+    at91_init_dbgu(sam9, serial_hds[0]);
+    at91_init_pitc(sam9);
+    at91_aic_init(sam9);
+    memset(sam9->usart0_regs, 0, sizeof(sam9->usart0_regs));
+
+    /*
+      we use variant of booting from external memory (NOR FLASH),
+      it mapped to 0x0 at start, and also it is accessable from 0x10000000 address
+    */
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (dinfo) {
+        ram_addr_t nor_flash_mem = qemu_ram_alloc(NOR_FLASH_SIZE);
+        if (!nor_flash_mem) {
+            fprintf(stderr, "allocation failed\n");
+            exit(EXIT_FAILURE);
+        }
+
+        sam9->norflash = pflash_cfi_atmel_register(AT91SAM9263EK_NORFLASH_OFF,
+                                                   nor_flash_mem,
+                                                   dinfo->bdrv,
+                                                   4 * 1024 * 2, 8,
+                                                   32 * 1024 * 2,
+                                                   (135 - 8),
+                                                   2, 0x001F, 0x01D6, 0, 0);
+
+        if (!sam9->norflash) {
+            fprintf(stderr, "qemu: error registering flash memory.\n");
+            exit(EXIT_FAILURE);
+        }
+
+        DEBUG("register flash at 0x0\n");
+        //register only part of flash, to prevent conflict with internal sram
+        cpu_register_physical_memory(0x0, 100 * 1024 /*NOR_FLASH_SIZE*/,
+                                     nor_flash_mem | IO_MEM_ROMD);
+    } else {
+        fprintf(stderr, "qemu: can not start without flash.\n");
+        exit(EXIT_FAILURE);
+    }
+    env->regs[15] = 0x0;
+}
+
+static QEMUMachine at91sam9263ek_machine = {
+    .name = "at91sam9263ek",
+    .desc = "Atmel at91sam9263ek board (ARM926EJ-S)",
+    .init = at91sam9_init,
+};
+
+static void at91sam9_machine_init(void)
+{
+    qemu_register_machine(&at91sam9263ek_machine);
+}
+
+machine_init(at91sam9_machine_init)
diff --git a/hw/at91sam9263_defs.h b/hw/at91sam9263_defs.h
new file mode 100644
index 0000000..c7136c3
--- /dev/null
+++ b/hw/at91sam9263_defs.h
@@ -0,0 +1,144 @@ 
+#ifndef _HW_AT91SAM9263_DEFS_H_
+#define _HW_AT91SAM9263_DEFS_H_
+
+/* base periph addresses */
+#define AT91_PERIPH_BASE     0xF0000000
+#define AT91_USART0_BASE     0xFFF8C000
+#define AT91_SDRAMC0_BASE    0xFFFFE200
+#define AT91_SMC0_BASE       0xFFFFE400
+#define AT91_ECC1_BASE       0xFFFFE600
+#define AT91_BUS_MATRIX_BASE 0xFFFFEC00
+#define AT91_CCFG_BASE       0xFFFFED10
+#define AT91_DBGU_BASE       0xFFFFEE00
+#define AT91_AIC_BASE        0xFFFFF000
+#define AT91_PIO_BASE        0xFFFFF200
+#define AT91_PMC_BASE        0xFFFFFC00
+#define AT91_RSTC_BASE       0xFFFFFD00
+#define AT91_PITC_BASE       0xFFFFFD30
+#define AT91_WDT_BASE        0xFFFFFD40
+
+/* PMC registers */
+#define AT91_PMC_SR (0x68 / sizeof(uint32_t))
+#define AT91_PMC_MCKR (0x0020 / sizeof(uint32_t))
+#define AT91_PMC_MOR (0x30 / sizeof(uint32_t))
+#define AT91_PMC_CSS             (0x3 <<  0) // (PMC) Programmable Clock Selection
+#define AT91_PMC_MCKRDY          (0x1 <<  3) // (PMC) Master Clock Status/Enable/Disable/Mask
+#define AT91_PMC_MOSCS           (0x1 <<  0) // (PMC) MOSC Status/Enable/Disable/Mask
+#define AT91_CKGR_MOSCEN         (0x1 <<  0) // (CKGR) Main Oscillator Enable
+#define AT91_PMC_PLLAR (0x0028 / sizeof(uint32_t))
+#define AT91_PMC_PLLBR (0x002C / sizeof(uint32_t))
+#define AT91_PMC_LOCKA           (0x1 <<  1) // (PMC) PLL A Status/Enable/Disable/Mask
+#define AT91_PMC_LOCKB           (0x1 <<  2) // (PMC) PLL B Status/Enable/Disable/Mask
+#define AT91_PMC_PCER (0x10 / sizeof(uint32_t))
+
+/*dbgu registers */
+#define AT91_DBGU_CR   0x0
+#define AT91_DBGU_MR   (4 / sizeof(uint32_t))
+#define AT91_DBGU_IER  (8 / sizeof(uint32_t))
+#define AT91_DBGU_IDR  (0xC / sizeof(uint32_t))
+#define AT91_DBGU_IMR  (0x10 / sizeof(uint32_t))
+#define AT91_DBGU_SR   (0x14 / sizeof(uint32_t))
+#define AT91_DBGU_RHR  (0x18 / sizeof(uint32_t))
+#define AT91_DBGU_THR  (0x001C / sizeof(uint32_t))
+#define AT91_DBGU_BRGR (0x0020 / sizeof(uint32_t))
+
+
+// -------- DBGU_CR : (DBGU Offset: 0x0) Debug Unit Control Register --------
+#define AT91_US_RSTRX            (0x1 <<  2) // (DBGU) Reset Receiver
+#define AT91_US_RSTTX            (0x1 <<  3) // (DBGU) Reset Transmitter
+#define AT91_US_RXEN             (0x1 <<  4) // (DBGU) Receiver Enable
+#define AT91_US_RXDIS            (0x1 <<  5) // (DBGU) Receiver Disable
+#define AT91_US_TXEN             (0x1 <<  6) // (DBGU) Transmitter Enable
+#define AT91_US_TXDIS            (0x1 <<  7) // (DBGU) Transmitter Disable
+#define AT91_US_RSTSTA           (0x1 <<  8) // (DBGU) Reset Status Bits
+// -------- DBGU_IER : (DBGU Offset: 0x8) Debug Unit Interrupt Enable Register --------
+#define AT91_US_RXRDY            (0x1 <<  0) // (DBGU) RXRDY Interrupt
+#define AT91_US_TXRDY            (0x1 <<  1) // (DBGU) TXRDY Interrupt
+#define AT91_US_ENDRX            (0x1 <<  3) // (DBGU) End of Receive Transfer Interrupt
+#define AT91_US_ENDTX            (0x1 <<  4) // (DBGU) End of Transmit Interrupt
+#define AT91_US_OVRE             (0x1 <<  5) // (DBGU) Overrun Interrupt
+#define AT91_US_FRAME            (0x1 <<  6) // (DBGU) Framing Error Interrupt
+#define AT91_US_PARE             (0x1 <<  7) // (DBGU) Parity Error Interrupt
+#define AT91_US_TXEMPTY          (0x1 <<  9) // (DBGU) TXEMPTY Interrupt
+#define AT91_US_TXBUFE           (0x1 << 11) // (DBGU) TXBUFE Interrupt
+#define AT91_US_RXBUFF           (0x1 << 12) // (DBGU) RXBUFF Interrupt
+#define AT91_US_COMM_TX          (0x1 << 30) // (DBGU) COMM_TX Interrupt
+#define AT91_US_COMM_RX          (0x1 << 31) // (DBGU) COMM_RX Interrupt
+
+/* US registers */
+#define AT91_US_CR  (0)
+#define AT91_US_MR  (4 / sizeof(uint32_t))
+#define AT91_US_IER (8 / sizeof(uint32_t))
+#define AT91_US_IDR (0xC / sizeof(uint32_t))
+#define AT91_US_IMR (0x10 / sizeof(uint32_t))
+
+/* matrix */
+
+// *****************************************************************************
+//              SOFTWARE API DEFINITION  FOR AHB Matrix Interface
+// *****************************************************************************
+// *** Register offset in AT91S_MATRIX structure ***
+#define MATRIX_MCFG0    ( 0) //  Master Configuration Register 0
+#define MATRIX_MCFG1    ( 4) //  Master Configuration Register 1
+#define MATRIX_MCFG2    ( 8) //  Master Configuration Register 2
+#define MATRIX_MCFG3    (12) //  Master Configuration Register 3
+#define MATRIX_MCFG4    (16) //  Master Configuration Register 4
+#define MATRIX_MCFG5    (20) //  Master Configuration Register 5
+#define MATRIX_MCFG6    (24) //  Master Configuration Register 6
+#define MATRIX_MCFG7    (28) //  Master Configuration Register 7
+#define MATRIX_MCFG8    (32) //  Master Configuration Register 8
+#define MATRIX_SCFG0    (64) //  Slave Configuration Register 0
+#define MATRIX_SCFG1    (68) //  Slave Configuration Register 1
+#define MATRIX_SCFG2    (72) //  Slave Configuration Register 2
+#define MATRIX_SCFG3    (76) //  Slave Configuration Register 3
+#define MATRIX_SCFG4    (80) //  Slave Configuration Register 4
+#define MATRIX_SCFG5    (84) //  Slave Configuration Register 5
+#define MATRIX_SCFG6    (88) //  Slave Configuration Register 6
+#define MATRIX_SCFG7    (92) //  Slave Configuration Register 7
+#define MATRIX_PRAS0    (128) //  PRAS0
+#define MATRIX_PRBS0    (132) //  PRBS0
+#define MATRIX_PRAS1    (136) //  PRAS1
+#define MATRIX_PRBS1    (140) //  PRBS1
+#define MATRIX_PRAS2    (144) //  PRAS2
+#define MATRIX_PRBS2    (148) //  PRBS2
+#define MATRIX_PRAS3    (152) //  PRAS3
+#define MATRIX_PRBS3    (156) //  PRBS3
+#define MATRIX_PRAS4    (160) //  PRAS4
+#define MATRIX_PRBS4    (164) //  PRBS4
+#define MATRIX_PRAS5    (168) //  PRAS5
+#define MATRIX_PRBS5    (172) //  PRBS5
+#define MATRIX_PRAS6    (176) //  PRAS6
+#define MATRIX_PRBS6    (180) //  PRBS6
+#define MATRIX_PRAS7    (184) //  PRAS7
+#define MATRIX_PRBS7    (188) //  PRBS7
+#define MATRIX_MRCR     (256) //  Master Remp Control Register
+
+#define AT91C_MATRIX_RCA926I      (0x1 <<  0) // (MATRIX) Remap Command Bit for ARM926EJ-S Instruction
+#define AT91C_MATRIX_RCA926D      (0x1 <<  1) // (MATRIX) Remap Command Bit for ARM926EJ-S Data
+#define AT91C_MATRIX_RCB2         (0x1 <<  2) // (MATRIX) Remap Command Bit for PDC
+#define AT91C_MATRIX_RCB3         (0x1 <<  3) // (MATRIX) Remap Command Bit for LCD
+#define AT91C_MATRIX_RCB4         (0x1 <<  4) // (MATRIX) Remap Command Bit for 2DGC
+#define AT91C_MATRIX_RCB5         (0x1 <<  5) // (MATRIX) Remap Command Bit for ISI
+#define AT91C_MATRIX_RCB6         (0x1 <<  6) // (MATRIX) Remap Command Bit for DMA
+#define AT91C_MATRIX_RCB7         (0x1 <<  7) // (MATRIX) Remap Command Bit for EMAC
+#define AT91C_MATRIX_RCB8         (0x1 <<  8) // (MATRIX) Remap Command Bit for USB
+
+/*pitc */
+#define AT91_PTIC_MR_PITEN  (1 << 24)
+#define AT91_PTIC_MR_PITIEN (1 << 25)
+#define AT91_PITC_MR      0
+#define AT91_PITC_SR   (0x4 / sizeof(uint32_t))
+#define AT91_PITC_PIVR (0x8 / sizeof(uint32_t))
+#define AT91_PITC_PIIR (0xC / sizeof(uint32_t))
+
+/*AIC registers*/
+#define AT91_AIC_SVR0  (0x80  / sizeof(uint32_t))
+#define AT91_AIC_ISR   (0x108 / sizeof(uint32_t))
+#define AT91_AIC_IECR  (0x120 / sizeof(uint32_t))
+#define AT91_AIC_EOICR (0x130 / sizeof(uint32_t))
+#define AT91_AIC_IVR   (0x100 / sizeof(uint32_t))
+#define AT91_AIC_IDCR  (0x124 / sizeof(uint32_t))
+
+#define AT91_PERIPH_SYS_ID 1
+
+#endif//!_HW_AT91SAM9263_DEFS_H_