Patchwork [v2,5/6] Emulation of Leon3.

login
register
mail settings
Submitter Fabien Chouteau
Date Jan. 3, 2011, 2:07 p.m.
Message ID <ea065516260c0fadd1ed30bf7c891b9b69918101.1294055704.git.chouteau@adacore.com>
Download mbox | patch
Permalink /patch/77269/
State New
Headers show

Comments

Fabien Chouteau - Jan. 3, 2011, 2:07 p.m.
Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 Makefile.target          |    5 +-
 hw/leon3.c               |  202 ++++++++++++++++++++++++++++++++++++++++++++++
 target-sparc/cpu.h       |   39 ++++++---
 target-sparc/helper.c    |    7 +-
 target-sparc/helper.h    |    1 +
 target-sparc/op_helper.c |  151 ++++++++++++++++++++++++++++++++++-
 target-sparc/translate.c |   14 +++-
 7 files changed, 397 insertions(+), 22 deletions(-)
Blue Swirl - Jan. 4, 2011, 6:56 p.m.
On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
>
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
> ---
>  Makefile.target          |    5 +-
>  hw/leon3.c               |  202 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-sparc/cpu.h       |   39 ++++++---
>  target-sparc/helper.c    |    7 +-
>  target-sparc/helper.h    |    1 +
>  target-sparc/op_helper.c |  151 ++++++++++++++++++++++++++++++++++-
>  target-sparc/translate.c |   14 +++-
>  7 files changed, 397 insertions(+), 22 deletions(-)
>
> diff --git a/Makefile.target b/Makefile.target
> index 2800f47..f40e04f 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -290,7 +290,10 @@ obj-sparc-y += cirrus_vga.o
>  else
>  obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
>  obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
> -obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
> +obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
> +
> +# GRLIB
> +obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
>  endif
>
>  obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
> diff --git a/hw/leon3.c b/hw/leon3.c
> new file mode 100644
> index 0000000..d5fe863
> --- /dev/null
> +++ b/hw/leon3.c
> @@ -0,0 +1,202 @@
> +/*
> + * QEMU Leon3 System Emulator
> + *
> + * Copyright (c) 2010-2011 AdaCore
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#include "hw.h"
> +#include "qemu-timer.h"
> +#include "qemu-char.h"
> +#include "sysemu.h"
> +#include "boards.h"
> +#include "loader.h"
> +#include "elf.h"
> +
> +#include "grlib.h"
> +
> +//#define DEBUG_LEON3
> +
> +#ifdef DEBUG_LEON3
> +#define DPRINTF(fmt, ...)                                       \
> +    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...)
> +#endif
> +
> +/* Default system clock.  */
> +#define CPU_CLK (40 * 1000 * 1000)
> +
> +#define PROM_FILENAME        "u-boot.bin"
> +
> +#define MAX_PILS 16
> +
> +typedef struct ResetData {
> +    CPUState *env;
> +    uint64_t  entry;            /* save kernel entry in case of reset */

uint32_t should be enough.

> +} ResetData;
> +
> +static void main_cpu_reset(void *opaque)
> +{
> +    ResetData *s = (ResetData *)opaque;
> +    assert(s != NULL);
> +    CPUState *env = s->env;
> +    assert(env != NULL);

These asserts won't ever trigger.

> +
> +    cpu_reset(env);
> +
> +    env->halted = 0;
> +    env->pc     = s->entry;
> +    env->npc    = s->entry + 4;
> +}
> +
> +static void leon3_irq_ack(void *irq_manager, int intno)
> +{
> +    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
> +    leon3_cache_control_int();
> +}
> +
> +static void leon3_generic_hw_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;
> +    ram_addr_t  ram_offset, prom_offset;
> +    int         ret;
> +    char       *filename;
> +    qemu_irq   *cpu_irqs = NULL;
> +    int         bios_size;
> +    int         prom_size;
> +    int         aligned_bios_size;
> +    ResetData  *reset_info;
> +
> +    /* Init CPU */
> +    if (!cpu_model) {
> +        cpu_model = "LEON3";
> +    }
> +
> +    env = cpu_init(cpu_model);
> +    if (!env) {
> +        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
> +        exit(1);
> +    }
> +
> +    cpu_sparc_set_id(env, 0);
> +
> +    /* Reset data */
> +    reset_info        = qemu_mallocz(sizeof(ResetData));
> +    reset_info->env   = env;
> +    qemu_register_reset(main_cpu_reset, reset_info);
> +
> +    /* Allocate IRQ manager */
> +    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS);
> +
> +    env->qemu_irq_ack = leon3_irq_ack;
> +
> +    /* Allocate RAM */
> +    if ((uint64_t)ram_size > (1UL << 30)) {
> +        fprintf(stderr,
> +                "qemu: Too much memory for this machine: %d, maximum 1G\n",
> +                (unsigned int)(ram_size / (1024 * 1024)));
> +        exit(1);
> +    }
> +
> +    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
> +    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
> +
> +    /* Allocate BIOS */
> +    prom_size = 8 * 1024 * 1024; /* 8Mb */
> +    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
> +    cpu_register_physical_memory(0x00000000, prom_size,
> +                                 prom_offset | IO_MEM_ROM);
> +
> +    /* Load boot prom */
> +    if (bios_name == NULL) {
> +        bios_name = PROM_FILENAME;
> +    }
> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> +
> +    bios_size = get_image_size(filename);
> +
> +    if (bios_size > prom_size) {
> +        fprintf(stderr, "qemu: could not load prom '%s': file too big \n",
> +                filename);
> +        exit(1);
> +    }
> +
> +    if (bios_size > 0) {
> +        aligned_bios_size =
> +            (bios_size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
> +
> +        ret = load_image_targphys(filename, 0x00000000, bios_size);
> +        if (ret < 0 || ret > prom_size) {
> +            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
> +            exit(1);
> +        }
> +    }
> +    else if (kernel_filename == NULL) {
> +        fprintf(stderr,"Can't read bios image %s\n", filename);
> +        exit(1);
> +    }
> +
> +    /* Can directly load an application. */
> +    if (kernel_filename != NULL) {
> +        long     kernel_size;
> +        uint64_t entry;

uint32_t

> +
> +        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
> +                               1 /* big endian */, ELF_MACHINE, 0);
> +        if (kernel_size < 0) {
> +            fprintf(stderr, "qemu: could not load kernel '%s'\n",
> +                    kernel_filename);
> +            exit(1);
> +        }
> +        if (bios_size <= 0) {
> +            /* If there is no bios/monitor, start the application.  */
> +            env->pc = entry;
> +            env->npc = entry + 4;
> +            reset_info->entry = entry;
> +        }
> +    }
> +
> +    /* Allocate timers */
> +    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
> +
> +    /* Allocate uart */
> +    if (serial_hds[0]) {
> +        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
> +    }
> +}
> +
> +QEMUMachine leon3_generic_machine = {
> +    .name     = "leon3_generic",
> +    .desc     = "Leon-3 generic",
> +    .init     = leon3_generic_hw_init,
> +    .use_scsi = 0,
> +};
> +
> +static void leon3_machine_init(void)
> +{
> +    qemu_register_machine(&leon3_generic_machine);
> +}
> +
> +machine_init(leon3_machine_init);
> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
> index 7e0d17c..7795be4 100644
> --- a/target-sparc/cpu.h
> +++ b/target-sparc/cpu.h
> @@ -251,20 +251,21 @@ typedef struct sparc_def_t {
>     uint32_t maxtl;
>  } sparc_def_t;
>
> -#define CPU_FEATURE_FLOAT    (1 << 0)
> -#define CPU_FEATURE_FLOAT128 (1 << 1)
> -#define CPU_FEATURE_SWAP     (1 << 2)
> -#define CPU_FEATURE_MUL      (1 << 3)
> -#define CPU_FEATURE_DIV      (1 << 4)
> -#define CPU_FEATURE_FLUSH    (1 << 5)
> -#define CPU_FEATURE_FSQRT    (1 << 6)
> -#define CPU_FEATURE_FMUL     (1 << 7)
> -#define CPU_FEATURE_VIS1     (1 << 8)
> -#define CPU_FEATURE_VIS2     (1 << 9)
> -#define CPU_FEATURE_FSMULD   (1 << 10)
> -#define CPU_FEATURE_HYPV     (1 << 11)
> -#define CPU_FEATURE_CMT      (1 << 12)
> -#define CPU_FEATURE_GL       (1 << 13)
> +#define CPU_FEATURE_FLOAT        (1 << 0)
> +#define CPU_FEATURE_FLOAT128     (1 << 1)
> +#define CPU_FEATURE_SWAP         (1 << 2)
> +#define CPU_FEATURE_MUL          (1 << 3)
> +#define CPU_FEATURE_DIV          (1 << 4)
> +#define CPU_FEATURE_FLUSH        (1 << 5)
> +#define CPU_FEATURE_FSQRT        (1 << 6)
> +#define CPU_FEATURE_FMUL         (1 << 7)
> +#define CPU_FEATURE_VIS1         (1 << 8)
> +#define CPU_FEATURE_VIS2         (1 << 9)
> +#define CPU_FEATURE_FSMULD       (1 << 10)
> +#define CPU_FEATURE_HYPV         (1 << 11)
> +#define CPU_FEATURE_CMT          (1 << 12)
> +#define CPU_FEATURE_GL           (1 << 13)
> +#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
>  #ifndef TARGET_SPARC64
>  #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
>                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
> @@ -436,6 +437,12 @@ typedef struct CPUSPARCState {
>  #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
>  #endif
>     sparc_def_t *def;
> +
> +    void *irq_manager;
> +    void (*qemu_irq_ack) (void *irq_manager, int intno);
> +
> +    /* Leon3 cache control */
> +    uint32_t cache_control;
>  } CPUSPARCState;
>
>  #ifndef NO_CPU_IO_DEFS
> @@ -471,6 +478,10 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
>  int cpu_cwp_dec(CPUState *env1, int cwp);
>  void cpu_set_cwp(CPUState *env1, int new_cwp);
>
> +void     leon3_cache_control_st(target_ulong addr, uint64_t val, int size);
> +uint64_t leon3_cache_control_ld(target_ulong addr, int size);
> +void     leon3_cache_control_int(void);

Is there any need to export these?

> +
>  /* sun4m.c, sun4u.c */
>  void cpu_check_irqs(CPUSPARCState *env);
>
> diff --git a/target-sparc/helper.c b/target-sparc/helper.c
> index e84c312..49bdb58 100644
> --- a/target-sparc/helper.c
> +++ b/target-sparc/helper.c
> @@ -784,6 +784,7 @@ void cpu_reset(CPUSPARCState *env)
>     env->pc = 0;
>     env->npc = env->pc + 4;
>  #endif
> +    env->cache_control = 0;
>  }
>
>  static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
> @@ -1288,20 +1289,20 @@ static const sparc_def_t sparc_defs[] = {
>         .mmu_sfsr_mask = 0xffffffff,
>         .mmu_trcr_mask = 0xffffffff,
>         .nwindows = 8,
> -        .features = CPU_DEFAULT_FEATURES,
> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>     },
>     {
>         .name = "LEON3",
>         .iu_version = 0xf3000000,
>         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
>         .mmu_version = 0xf3000000,
> -        .mmu_bm = 0x00004000,
> +        .mmu_bm = 0x00000000,
>         .mmu_ctpr_mask = 0x007ffff0,
>         .mmu_cxr_mask = 0x0000003f,
>         .mmu_sfsr_mask = 0xffffffff,
>         .mmu_trcr_mask = 0xffffffff,
>         .nwindows = 8,
> -        .features = CPU_DEFAULT_FEATURES,
> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>     },
>  #endif
>  };
> diff --git a/target-sparc/helper.h b/target-sparc/helper.h
> index 6f103e7..004eaaa 100644
> --- a/target-sparc/helper.h
> +++ b/target-sparc/helper.h
> @@ -83,6 +83,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
>  DEF_HELPER_0(fcmpeq_fcc3, void)
>  #endif
>  DEF_HELPER_1(raise_exception, void, int)
> +DEF_HELPER_0(shutdown, void)
>  #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
>  #define F_HELPER_DQ_0_0(name)                   \
>     F_HELPER_0_0(name ## d);                    \
> diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
> index be3c1e0..0390aec 100644
> --- a/target-sparc/op_helper.c
> +++ b/target-sparc/op_helper.c
> @@ -1,6 +1,7 @@
>  #include "exec.h"
>  #include "host-utils.h"
>  #include "helper.h"
> +#include "sysemu.h"
>
>  //#define DEBUG_MMU
>  //#define DEBUG_MXCC
> @@ -9,6 +10,7 @@
>  //#define DEBUG_ASI
>  //#define DEBUG_PCALL
>  //#define DEBUG_PSTATE
> +//#define DEBUG_CACHE_CONTROL
>
>  #ifdef DEBUG_MMU
>  #define DPRINTF_MMU(fmt, ...)                                   \
> @@ -36,6 +38,13 @@
>  #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
>  #endif
>
> +#ifdef DEBUG_CACHE_CONTROL
> +#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
> +    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
> +#endif
> +
>  #ifdef TARGET_SPARC64
>  #ifndef TARGET_ABI32
>  #define AM_CHECK(env1) ((env1)->pstate & PS_AM)
> @@ -294,6 +303,11 @@ void HELPER(raise_exception)(int tt)
>     raise_exception(tt);
>  }
>
> +void helper_shutdown(void)
> +{
> +    qemu_system_shutdown_request();
> +}
> +
>  void helper_check_align(target_ulong addr, uint32_t align)
>  {
>     if (addr & align) {
> @@ -1609,8 +1623,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
>
>     helper_check_align(addr, size - 1);
>     switch (asi) {
> -    case 2: /* SuperSparc MXCC registers */
> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>         switch (addr) {
> +        case 0x00:          /* Leon3 Cache Control */
> +        case 0x08:          /* Leon3 Instruction Cache config */
> +        case 0x0C:          /* Leon3 Date Cache config */
> +            ret = leon3_cache_control_ld(addr, size);
> +            break;
>         case 0x01c00a00: /* MXCC control register */
>             if (size == 8)
>                 ret = env->mxccregs[3];
> @@ -1838,8 +1857,14 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
>  {
>     helper_check_align(addr, size - 1);
>     switch(asi) {
> -    case 2: /* SuperSparc MXCC registers */
> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>         switch (addr) {
> +        case 0x00:          /* Leon3 Cache Control */
> +        case 0x08:          /* Leon3 Instruction Cache config */
> +        case 0x0C:          /* Leon3 Date Cache config */
> +            leon3_cache_control_st(addr, val, size);
> +            break;
> +
>         case 0x01c00000: /* MXCC stream data register 0 */
>             if (size == 8)
>                 env->mxccdata[0] = val;
> @@ -4135,6 +4160,13 @@ void do_interrupt(CPUState *env)
>     env->pc = env->tbr;
>     env->npc = env->pc + 4;
>     env->exception_index = -1;
> +
> +#if !defined(CONFIG_USER_ONLY)
> +    /* IRQ acknowledgment */
> +    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
> +        env->qemu_irq_ack(env->irq_manager, intno);
> +    }
> +#endif
>  }
>  #endif
>
> @@ -4329,3 +4361,118 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
>  #endif
>  }
>  #endif
> +
> +/* Leon3 cache control */
> +
> +/* Cache control: emulate the behavior of cache control registers but without
> +   any effect on the emulated CPU */
> +
> +#define CACHE_STATE_MASK 0x3
> +#define CACHE_DISABLED   0x0
> +#define CACHE_FROZEN     0x1
> +#define CACHE_ENABLED    0x3
> +
> +/* Cache Control register fields */
> +
> +#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
> +#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
> +#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
> +#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
> +#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
> +#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
> +#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
> +#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */

These should be at the top of the file.

> +
> +
> +void leon3_cache_control_int(void)
> +{
> +    uint32_t state = 0;
> +
> +    if (env->cache_control & CACHE_CTRL_IF) {
> +        /* Instruction cache state */
> +        state = env->cache_control & CACHE_STATE_MASK;
> +        if (state == CACHE_ENABLED) {
> +            state = CACHE_FROZEN;
> +            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
> +        }
> +
> +        env->cache_control &= ~CACHE_STATE_MASK;
> +        env->cache_control |= state;
> +    }
> +
> +    if (env->cache_control & CACHE_CTRL_DF) {
> +        /* Data cache state */
> +        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
> +        if (state == CACHE_ENABLED) {
> +            state = CACHE_FROZEN;
> +            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
> +        }
> +
> +        env->cache_control &= ~(CACHE_STATE_MASK << 2);
> +        env->cache_control |= (state << 2);
> +    }
> +}
> +
> +void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
> +{
> +    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
> +                          addr, val, size);
> +
> +    if (size != 4) {
> +        DPRINTF_CACHE_CONTROL("32bits only\n");
> +        return;
> +    }
> +
> +    switch (addr) {
> +        case 0x00:              /* Cache control */
> +
> +            /* These values must always be read as zeros */
> +            val &= ~CACHE_CTRL_FD;
> +            val &= ~CACHE_CTRL_FI;
> +            val &= ~CACHE_CTRL_IB;
> +            val &= ~CACHE_CTRL_IP;
> +            val &= ~CACHE_CTRL_DP;
> +
> +            env->cache_control = val;
> +            break;
> +        case 0x04:              /* Instruction cache configuration */
> +        case 0x08:              /* Data cache configuration */
> +            /* Read Only */
> +            break;
> +        default:
> +            DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
> +            break;
> +    };
> +}
> +
> +uint64_t leon3_cache_control_ld(target_ulong addr, int size)
> +{
> +    uint64_t ret = 0;
> +
> +    if (size != 4) {
> +        DPRINTF_CACHE_CONTROL("32bits only\n");
> +        return 0;
> +    }
> +
> +    switch (addr) {
> +        case 0x00:              /* Cache control */
> +            ret = env->cache_control;
> +            break;
> +
> +            /* Configuration registers are read and only always keep those
> +               predefined values */
> +
> +        case 0x04:              /* Instruction cache configuration */
> +            ret = 0x10220000;
> +            break;
> +        case 0x08:              /* Data cache configuration */
> +            ret = 0x18220000;
> +            break;
> +        default:
> +            DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
> +            break;
> +    };
> +    DPRINTF_CACHE_CONTROL("st addr:%08x, ret:%" PRIx64 ", size:%d\n",
> +                          addr, ret, size);
> +    return ret;
> +}
> diff --git a/target-sparc/translate.c b/target-sparc/translate.c
> index 23f9519..b0e8044 100644
> --- a/target-sparc/translate.c
> +++ b/target-sparc/translate.c
> @@ -1997,8 +1997,9 @@ static void disas_sparc_insn(DisasContext * dc)
>                     } else
>                         tcg_gen_mov_tl(cpu_dst, cpu_src1);
>                 }
> +
>                 cond = GET_FIELD(insn, 3, 6);
> -                if (cond == 0x8) {
> +                if (cond == 0x8) { /* Trap Always */
>                     save_state(dc, cpu_cond);
>                     if ((dc->def->features & CPU_FEATURE_HYPV) &&
>                         supervisor(dc))
> @@ -2007,7 +2008,16 @@ static void disas_sparc_insn(DisasContext * dc)
>                         tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
>                     tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
>                     tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
> -                    gen_helper_raise_exception(cpu_tmp32);
> +
> +                    if (rs2 == 0
> +                          &&

Please merge with the next or previous line.

> +                        dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
> +
> +                        gen_helper_shutdown();
> +
> +                    } else {
> +                        gen_helper_raise_exception(cpu_tmp32);
> +                    }
>                 } else if (cond != 0) {
>                     TCGv r_cond = tcg_temp_new();
>                     int l1;
> --
> 1.7.1
>
>
>
Fabien Chouteau - Jan. 17, 2011, 4:01 p.m.
On 01/04/2011 07:56 PM, Blue Swirl wrote:
> On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau<chouteau@adacore.com>  wrote:
>> diff --git a/hw/leon3.c b/hw/leon3.c
>> new file mode 100644
>> index 0000000..d5fe863
>> --- /dev/null
>> +++ b/hw/leon3.c
>> @@ -0,0 +1,202 @@
>> +/*
>> + * QEMU Leon3 System Emulator
>> + *
>> + * Copyright (c) 2010-2011 AdaCore
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + */
>> +#include "hw.h"
>> +#include "qemu-timer.h"
>> +#include "qemu-char.h"
>> +#include "sysemu.h"
>> +#include "boards.h"
>> +#include "loader.h"
>> +#include "elf.h"
>> +
>> +#include "grlib.h"
>> +
>> +//#define DEBUG_LEON3
>> +
>> +#ifdef DEBUG_LEON3
>> +#define DPRINTF(fmt, ...)                                       \
>> +    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
>> +#else
>> +#define DPRINTF(fmt, ...)
>> +#endif
>> +
>> +/* Default system clock.  */
>> +#define CPU_CLK (40 * 1000 * 1000)
>> +
>> +#define PROM_FILENAME        "u-boot.bin"
>> +
>> +#define MAX_PILS 16
>> +
>> +typedef struct ResetData {
>> +    CPUState *env;
>> +    uint64_t  entry;            /* save kernel entry in case of reset */
>
> uint32_t should be enough.
>
>> +} ResetData;
>> +
>> +static void main_cpu_reset(void *opaque)
>> +{
>> +    ResetData *s = (ResetData *)opaque;
>> +    assert(s != NULL);
>> +    CPUState *env = s->env;
>> +    assert(env != NULL);
>
> These asserts won't ever trigger.
>
>> +
>> +    cpu_reset(env);
>> +
>> +    env->halted = 0;
>> +    env->pc     = s->entry;
>> +    env->npc    = s->entry + 4;
>> +}
>> +
>> +static void leon3_irq_ack(void *irq_manager, int intno)
>> +{
>> +    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
>> +    leon3_cache_control_int();
>> +}
>> +
>> +static void leon3_generic_hw_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;
>> +    ram_addr_t  ram_offset, prom_offset;
>> +    int         ret;
>> +    char       *filename;
>> +    qemu_irq   *cpu_irqs = NULL;
>> +    int         bios_size;
>> +    int         prom_size;
>> +    int         aligned_bios_size;
>> +    ResetData  *reset_info;
>> +
>> +    /* Init CPU */
>> +    if (!cpu_model) {
>> +        cpu_model = "LEON3";
>> +    }
>> +
>> +    env = cpu_init(cpu_model);
>> +    if (!env) {
>> +        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
>> +        exit(1);
>> +    }
>> +
>> +    cpu_sparc_set_id(env, 0);
>> +
>> +    /* Reset data */
>> +    reset_info        = qemu_mallocz(sizeof(ResetData));
>> +    reset_info->env   = env;
>> +    qemu_register_reset(main_cpu_reset, reset_info);
>> +
>> +    /* Allocate IRQ manager */
>> +    grlib_irqmp_create(0x80000200, env,&cpu_irqs, MAX_PILS);
>> +
>> +    env->qemu_irq_ack = leon3_irq_ack;
>> +
>> +    /* Allocate RAM */
>> +    if ((uint64_t)ram_size>  (1UL<<  30)) {
>> +        fprintf(stderr,
>> +                "qemu: Too much memory for this machine: %d, maximum 1G\n",
>> +                (unsigned int)(ram_size / (1024 * 1024)));
>> +        exit(1);
>> +    }
>> +
>> +    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
>> +    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
>> +
>> +    /* Allocate BIOS */
>> +    prom_size = 8 * 1024 * 1024; /* 8Mb */
>> +    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
>> +    cpu_register_physical_memory(0x00000000, prom_size,
>> +                                 prom_offset | IO_MEM_ROM);
>> +
>> +    /* Load boot prom */
>> +    if (bios_name == NULL) {
>> +        bios_name = PROM_FILENAME;
>> +    }
>> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>> +
>> +    bios_size = get_image_size(filename);
>> +
>> +    if (bios_size>  prom_size) {
>> +        fprintf(stderr, "qemu: could not load prom '%s': file too big \n",
>> +                filename);
>> +        exit(1);
>> +    }
>> +
>> +    if (bios_size>  0) {
>> +        aligned_bios_size =
>> +            (bios_size + TARGET_PAGE_SIZE - 1)&  TARGET_PAGE_MASK;
>> +
>> +        ret = load_image_targphys(filename, 0x00000000, bios_size);
>> +        if (ret<  0 || ret>  prom_size) {
>> +            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
>> +            exit(1);
>> +        }
>> +    }
>> +    else if (kernel_filename == NULL) {
>> +        fprintf(stderr,"Can't read bios image %s\n", filename);
>> +        exit(1);
>> +    }
>> +
>> +    /* Can directly load an application. */
>> +    if (kernel_filename != NULL) {
>> +        long     kernel_size;
>> +        uint64_t entry;
>
> uint32_t
>

load_elf expects an uint32_t.

>> +
>> +        kernel_size = load_elf(kernel_filename, NULL, NULL,&entry, NULL, NULL,
>> +                               1 /* big endian */, ELF_MACHINE, 0);
>> +        if (kernel_size<  0) {
>> +            fprintf(stderr, "qemu: could not load kernel '%s'\n",
>> +                    kernel_filename);
>> +            exit(1);
>> +        }
>> +        if (bios_size<= 0) {
>> +            /* If there is no bios/monitor, start the application.  */
>> +            env->pc = entry;
>> +            env->npc = entry + 4;
>> +            reset_info->entry = entry;
>> +        }
>> +    }
>> +
>> +    /* Allocate timers */
>> +    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
>> +
>> +    /* Allocate uart */
>> +    if (serial_hds[0]) {
>> +        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
>> +    }
>> +}
>> +
>> +QEMUMachine leon3_generic_machine = {
>> +    .name     = "leon3_generic",
>> +    .desc     = "Leon-3 generic",
>> +    .init     = leon3_generic_hw_init,
>> +    .use_scsi = 0,
>> +};
>> +
>> +static void leon3_machine_init(void)
>> +{
>> +    qemu_register_machine(&leon3_generic_machine);
>> +}
>> +
>> +machine_init(leon3_machine_init);
>> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
>> index 7e0d17c..7795be4 100644
>> --- a/target-sparc/cpu.h
>> +++ b/target-sparc/cpu.h
>> @@ -251,20 +251,21 @@ typedef struct sparc_def_t {
>>      uint32_t maxtl;
>>   } sparc_def_t;
>>
>> -#define CPU_FEATURE_FLOAT    (1<<  0)
>> -#define CPU_FEATURE_FLOAT128 (1<<  1)
>> -#define CPU_FEATURE_SWAP     (1<<  2)
>> -#define CPU_FEATURE_MUL      (1<<  3)
>> -#define CPU_FEATURE_DIV      (1<<  4)
>> -#define CPU_FEATURE_FLUSH    (1<<  5)
>> -#define CPU_FEATURE_FSQRT    (1<<  6)
>> -#define CPU_FEATURE_FMUL     (1<<  7)
>> -#define CPU_FEATURE_VIS1     (1<<  8)
>> -#define CPU_FEATURE_VIS2     (1<<  9)
>> -#define CPU_FEATURE_FSMULD   (1<<  10)
>> -#define CPU_FEATURE_HYPV     (1<<  11)
>> -#define CPU_FEATURE_CMT      (1<<  12)
>> -#define CPU_FEATURE_GL       (1<<  13)
>> +#define CPU_FEATURE_FLOAT        (1<<  0)
>> +#define CPU_FEATURE_FLOAT128     (1<<  1)
>> +#define CPU_FEATURE_SWAP         (1<<  2)
>> +#define CPU_FEATURE_MUL          (1<<  3)
>> +#define CPU_FEATURE_DIV          (1<<  4)
>> +#define CPU_FEATURE_FLUSH        (1<<  5)
>> +#define CPU_FEATURE_FSQRT        (1<<  6)
>> +#define CPU_FEATURE_FMUL         (1<<  7)
>> +#define CPU_FEATURE_VIS1         (1<<  8)
>> +#define CPU_FEATURE_VIS2         (1<<  9)
>> +#define CPU_FEATURE_FSMULD       (1<<  10)
>> +#define CPU_FEATURE_HYPV         (1<<  11)
>> +#define CPU_FEATURE_CMT          (1<<  12)
>> +#define CPU_FEATURE_GL           (1<<  13)
>> +#define CPU_FEATURE_TA0_SHUTDOWN (1<<  14) /* Shutdown on "ta 0x0" */
>>   #ifndef TARGET_SPARC64
>>   #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
>>                                CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
>> @@ -436,6 +437,12 @@ typedef struct CPUSPARCState {
>>   #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
>>   #endif
>>      sparc_def_t *def;
>> +
>> +    void *irq_manager;
>> +    void (*qemu_irq_ack) (void *irq_manager, int intno);
>> +
>> +    /* Leon3 cache control */
>> +    uint32_t cache_control;
>>   } CPUSPARCState;
>>
>>   #ifndef NO_CPU_IO_DEFS
>> @@ -471,6 +478,10 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
>>   int cpu_cwp_dec(CPUState *env1, int cwp);
>>   void cpu_set_cwp(CPUState *env1, int new_cwp);
>>
>> +void     leon3_cache_control_st(target_ulong addr, uint64_t val, int size);
>> +uint64_t leon3_cache_control_ld(target_ulong addr, int size);
>> +void     leon3_cache_control_int(void);
>
> Is there any need to export these?
>

The last one needs to be exported, the others can be forward declaration 
in op_helper.c.

>> +
>>   /* sun4m.c, sun4u.c */
>>   void cpu_check_irqs(CPUSPARCState *env);
>>
>> diff --git a/target-sparc/helper.c b/target-sparc/helper.c
>> index e84c312..49bdb58 100644
>> --- a/target-sparc/helper.c
>> +++ b/target-sparc/helper.c
>> @@ -784,6 +784,7 @@ void cpu_reset(CPUSPARCState *env)
>>      env->pc = 0;
>>      env->npc = env->pc + 4;
>>   #endif
>> +    env->cache_control = 0;
>>   }
>>
>>   static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
>> @@ -1288,20 +1289,20 @@ static const sparc_def_t sparc_defs[] = {
>>          .mmu_sfsr_mask = 0xffffffff,
>>          .mmu_trcr_mask = 0xffffffff,
>>          .nwindows = 8,
>> -        .features = CPU_DEFAULT_FEATURES,
>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>      },
>>      {
>>          .name = "LEON3",
>>          .iu_version = 0xf3000000,
>>          .fpu_version = 4<<  17, /* FPU version 4 (Meiko) */
>>          .mmu_version = 0xf3000000,
>> -        .mmu_bm = 0x00004000,
>> +        .mmu_bm = 0x00000000,
>>          .mmu_ctpr_mask = 0x007ffff0,
>>          .mmu_cxr_mask = 0x0000003f,
>>          .mmu_sfsr_mask = 0xffffffff,
>>          .mmu_trcr_mask = 0xffffffff,
>>          .nwindows = 8,
>> -        .features = CPU_DEFAULT_FEATURES,
>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>      },
>>   #endif
>>   };
>> diff --git a/target-sparc/helper.h b/target-sparc/helper.h
>> index 6f103e7..004eaaa 100644
>> --- a/target-sparc/helper.h
>> +++ b/target-sparc/helper.h
>> @@ -83,6 +83,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
>>   DEF_HELPER_0(fcmpeq_fcc3, void)
>>   #endif
>>   DEF_HELPER_1(raise_exception, void, int)
>> +DEF_HELPER_0(shutdown, void)
>>   #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
>>   #define F_HELPER_DQ_0_0(name)                   \
>>      F_HELPER_0_0(name ## d);                    \
>> diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
>> index be3c1e0..0390aec 100644
>> --- a/target-sparc/op_helper.c
>> +++ b/target-sparc/op_helper.c
>> @@ -1,6 +1,7 @@
>>   #include "exec.h"
>>   #include "host-utils.h"
>>   #include "helper.h"
>> +#include "sysemu.h"
>>
>>   //#define DEBUG_MMU
>>   //#define DEBUG_MXCC
>> @@ -9,6 +10,7 @@
>>   //#define DEBUG_ASI
>>   //#define DEBUG_PCALL
>>   //#define DEBUG_PSTATE
>> +//#define DEBUG_CACHE_CONTROL
>>
>>   #ifdef DEBUG_MMU
>>   #define DPRINTF_MMU(fmt, ...)                                   \
>> @@ -36,6 +38,13 @@
>>   #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
>>   #endif
>>
>> +#ifdef DEBUG_CACHE_CONTROL
>> +#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
>> +    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
>> +#else
>> +#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
>> +#endif
>> +
>>   #ifdef TARGET_SPARC64
>>   #ifndef TARGET_ABI32
>>   #define AM_CHECK(env1) ((env1)->pstate&  PS_AM)
>> @@ -294,6 +303,11 @@ void HELPER(raise_exception)(int tt)
>>      raise_exception(tt);
>>   }
>>
>> +void helper_shutdown(void)
>> +{
>> +    qemu_system_shutdown_request();
>> +}
>> +
>>   void helper_check_align(target_ulong addr, uint32_t align)
>>   {
>>      if (addr&  align) {
>> @@ -1609,8 +1623,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
>>
>>      helper_check_align(addr, size - 1);
>>      switch (asi) {
>> -    case 2: /* SuperSparc MXCC registers */
>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>          switch (addr) {
>> +        case 0x00:          /* Leon3 Cache Control */
>> +        case 0x08:          /* Leon3 Instruction Cache config */
>> +        case 0x0C:          /* Leon3 Date Cache config */
>> +            ret = leon3_cache_control_ld(addr, size);
>> +            break;
>>          case 0x01c00a00: /* MXCC control register */
>>              if (size == 8)
>>                  ret = env->mxccregs[3];
>> @@ -1838,8 +1857,14 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
>>   {
>>      helper_check_align(addr, size - 1);
>>      switch(asi) {
>> -    case 2: /* SuperSparc MXCC registers */
>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>          switch (addr) {
>> +        case 0x00:          /* Leon3 Cache Control */
>> +        case 0x08:          /* Leon3 Instruction Cache config */
>> +        case 0x0C:          /* Leon3 Date Cache config */
>> +            leon3_cache_control_st(addr, val, size);
>> +            break;
>> +
>>          case 0x01c00000: /* MXCC stream data register 0 */
>>              if (size == 8)
>>                  env->mxccdata[0] = val;
>> @@ -4135,6 +4160,13 @@ void do_interrupt(CPUState *env)
>>      env->pc = env->tbr;
>>      env->npc = env->pc + 4;
>>      env->exception_index = -1;
>> +
>> +#if !defined(CONFIG_USER_ONLY)
>> +    /* IRQ acknowledgment */
>> +    if ((intno&  ~15) == TT_EXTINT&&  env->qemu_irq_ack != NULL) {
>> +        env->qemu_irq_ack(env->irq_manager, intno);
>> +    }
>> +#endif
>>   }
>>   #endif
>>
>> @@ -4329,3 +4361,118 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
>>   #endif
>>   }
>>   #endif
>> +
>> +/* Leon3 cache control */
>> +
>> +/* Cache control: emulate the behavior of cache control registers but without
>> +   any effect on the emulated CPU */
>> +
>> +#define CACHE_STATE_MASK 0x3
>> +#define CACHE_DISABLED   0x0
>> +#define CACHE_FROZEN     0x1
>> +#define CACHE_ENABLED    0x3
>> +
>> +/* Cache Control register fields */
>> +
>> +#define CACHE_CTRL_IF (1<<    4)  /* Instruction Cache Freeze on Interrupt */
>> +#define CACHE_CTRL_DF (1<<    5)  /* Data Cache Freeze on Interrupt */
>> +#define CACHE_CTRL_DP (1<<  14)  /* Data cache flush pending */
>> +#define CACHE_CTRL_IP (1<<  15)  /* Instruction cache flush pending */
>> +#define CACHE_CTRL_IB (1<<  16)  /* Instruction burst fetch */
>> +#define CACHE_CTRL_FI (1<<  21)  /* Flush Instruction cache (Write only) */
>> +#define CACHE_CTRL_FD (1<<  22)  /* Flush Data cache (Write only) */
>> +#define CACHE_CTRL_DS (1<<  23)  /* Data cache snoop enable */
>
> These should be at the top of the file.
>

I just want to put all the cache control code together, it's easier to read.
Blue Swirl - Jan. 17, 2011, 7:55 p.m.
On Mon, Jan 17, 2011 at 4:01 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
> On 01/04/2011 07:56 PM, Blue Swirl wrote:
>>
>> On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau<chouteau@adacore.com>
>>  wrote:
>>>
>>> diff --git a/hw/leon3.c b/hw/leon3.c
>>> new file mode 100644
>>> index 0000000..d5fe863
>>> --- /dev/null
>>> +++ b/hw/leon3.c
>>> @@ -0,0 +1,202 @@
>>> +/*
>>> + * QEMU Leon3 System Emulator
>>> + *
>>> + * Copyright (c) 2010-2011 AdaCore
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>> a copy
>>> + * of this software and associated documentation files (the "Software"),
>>> to deal
>>> + * in the Software without restriction, including without limitation the
>>> rights
>>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or
>>> sell
>>> + * copies of the Software, and to permit persons to whom the Software is
>>> + * furnished to do so, subject to the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice shall be
>>> included in
>>> + * all copies or substantial portions of the Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>> EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>> MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>>> SHALL
>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>> OTHER
>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>> ARISING FROM,
>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>>> DEALINGS IN
>>> + * THE SOFTWARE.
>>> + */
>>> +#include "hw.h"
>>> +#include "qemu-timer.h"
>>> +#include "qemu-char.h"
>>> +#include "sysemu.h"
>>> +#include "boards.h"
>>> +#include "loader.h"
>>> +#include "elf.h"
>>> +
>>> +#include "grlib.h"
>>> +
>>> +//#define DEBUG_LEON3
>>> +
>>> +#ifdef DEBUG_LEON3
>>> +#define DPRINTF(fmt, ...)                                       \
>>> +    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
>>> +#else
>>> +#define DPRINTF(fmt, ...)
>>> +#endif
>>> +
>>> +/* Default system clock.  */
>>> +#define CPU_CLK (40 * 1000 * 1000)
>>> +
>>> +#define PROM_FILENAME        "u-boot.bin"
>>> +
>>> +#define MAX_PILS 16
>>> +
>>> +typedef struct ResetData {
>>> +    CPUState *env;
>>> +    uint64_t  entry;            /* save kernel entry in case of reset */
>>
>> uint32_t should be enough.
>>
>>> +} ResetData;
>>> +
>>> +static void main_cpu_reset(void *opaque)
>>> +{
>>> +    ResetData *s = (ResetData *)opaque;
>>> +    assert(s != NULL);
>>> +    CPUState *env = s->env;
>>> +    assert(env != NULL);
>>
>> These asserts won't ever trigger.
>>
>>> +
>>> +    cpu_reset(env);
>>> +
>>> +    env->halted = 0;
>>> +    env->pc     = s->entry;
>>> +    env->npc    = s->entry + 4;
>>> +}
>>> +
>>> +static void leon3_irq_ack(void *irq_manager, int intno)
>>> +{
>>> +    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
>>> +    leon3_cache_control_int();
>>> +}
>>> +
>>> +static void leon3_generic_hw_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;
>>> +    ram_addr_t  ram_offset, prom_offset;
>>> +    int         ret;
>>> +    char       *filename;
>>> +    qemu_irq   *cpu_irqs = NULL;
>>> +    int         bios_size;
>>> +    int         prom_size;
>>> +    int         aligned_bios_size;
>>> +    ResetData  *reset_info;
>>> +
>>> +    /* Init CPU */
>>> +    if (!cpu_model) {
>>> +        cpu_model = "LEON3";
>>> +    }
>>> +
>>> +    env = cpu_init(cpu_model);
>>> +    if (!env) {
>>> +        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
>>> +        exit(1);
>>> +    }
>>> +
>>> +    cpu_sparc_set_id(env, 0);
>>> +
>>> +    /* Reset data */
>>> +    reset_info        = qemu_mallocz(sizeof(ResetData));
>>> +    reset_info->env   = env;
>>> +    qemu_register_reset(main_cpu_reset, reset_info);
>>> +
>>> +    /* Allocate IRQ manager */
>>> +    grlib_irqmp_create(0x80000200, env,&cpu_irqs, MAX_PILS);
>>> +
>>> +    env->qemu_irq_ack = leon3_irq_ack;
>>> +
>>> +    /* Allocate RAM */
>>> +    if ((uint64_t)ram_size>  (1UL<<  30)) {
>>> +        fprintf(stderr,
>>> +                "qemu: Too much memory for this machine: %d, maximum
>>> 1G\n",
>>> +                (unsigned int)(ram_size / (1024 * 1024)));
>>> +        exit(1);
>>> +    }
>>> +
>>> +    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
>>> +    cpu_register_physical_memory(0x40000000, ram_size, ram_offset |
>>> IO_MEM_RAM);
>>> +
>>> +    /* Allocate BIOS */
>>> +    prom_size = 8 * 1024 * 1024; /* 8Mb */
>>> +    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
>>> +    cpu_register_physical_memory(0x00000000, prom_size,
>>> +                                 prom_offset | IO_MEM_ROM);
>>> +
>>> +    /* Load boot prom */
>>> +    if (bios_name == NULL) {
>>> +        bios_name = PROM_FILENAME;
>>> +    }
>>> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>> +
>>> +    bios_size = get_image_size(filename);
>>> +
>>> +    if (bios_size>  prom_size) {
>>> +        fprintf(stderr, "qemu: could not load prom '%s': file too big
>>> \n",
>>> +                filename);
>>> +        exit(1);
>>> +    }
>>> +
>>> +    if (bios_size>  0) {
>>> +        aligned_bios_size =
>>> +            (bios_size + TARGET_PAGE_SIZE - 1)&  TARGET_PAGE_MASK;
>>> +
>>> +        ret = load_image_targphys(filename, 0x00000000, bios_size);
>>> +        if (ret<  0 || ret>  prom_size) {
>>> +            fprintf(stderr, "qemu: could not load prom '%s'\n",
>>> filename);
>>> +            exit(1);
>>> +        }
>>> +    }
>>> +    else if (kernel_filename == NULL) {
>>> +        fprintf(stderr,"Can't read bios image %s\n", filename);
>>> +        exit(1);
>>> +    }
>>> +
>>> +    /* Can directly load an application. */
>>> +    if (kernel_filename != NULL) {
>>> +        long     kernel_size;
>>> +        uint64_t entry;
>>
>> uint32_t
>>
>
> load_elf expects an uint32_t.

I think you mean uint64_t. It's OK then.

>>> +
>>> +        kernel_size = load_elf(kernel_filename, NULL, NULL,&entry, NULL,
>>> NULL,
>>> +                               1 /* big endian */, ELF_MACHINE, 0);
>>> +        if (kernel_size<  0) {
>>> +            fprintf(stderr, "qemu: could not load kernel '%s'\n",
>>> +                    kernel_filename);
>>> +            exit(1);
>>> +        }
>>> +        if (bios_size<= 0) {
>>> +            /* If there is no bios/monitor, start the application.  */
>>> +            env->pc = entry;
>>> +            env->npc = entry + 4;
>>> +            reset_info->entry = entry;
>>> +        }
>>> +    }
>>> +
>>> +    /* Allocate timers */
>>> +    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
>>> +
>>> +    /* Allocate uart */
>>> +    if (serial_hds[0]) {
>>> +        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
>>> +    }
>>> +}
>>> +
>>> +QEMUMachine leon3_generic_machine = {
>>> +    .name     = "leon3_generic",
>>> +    .desc     = "Leon-3 generic",
>>> +    .init     = leon3_generic_hw_init,
>>> +    .use_scsi = 0,
>>> +};
>>> +
>>> +static void leon3_machine_init(void)
>>> +{
>>> +    qemu_register_machine(&leon3_generic_machine);
>>> +}
>>> +
>>> +machine_init(leon3_machine_init);
>>> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
>>> index 7e0d17c..7795be4 100644
>>> --- a/target-sparc/cpu.h
>>> +++ b/target-sparc/cpu.h
>>> @@ -251,20 +251,21 @@ typedef struct sparc_def_t {
>>>     uint32_t maxtl;
>>>  } sparc_def_t;
>>>
>>> -#define CPU_FEATURE_FLOAT    (1<<  0)
>>> -#define CPU_FEATURE_FLOAT128 (1<<  1)
>>> -#define CPU_FEATURE_SWAP     (1<<  2)
>>> -#define CPU_FEATURE_MUL      (1<<  3)
>>> -#define CPU_FEATURE_DIV      (1<<  4)
>>> -#define CPU_FEATURE_FLUSH    (1<<  5)
>>> -#define CPU_FEATURE_FSQRT    (1<<  6)
>>> -#define CPU_FEATURE_FMUL     (1<<  7)
>>> -#define CPU_FEATURE_VIS1     (1<<  8)
>>> -#define CPU_FEATURE_VIS2     (1<<  9)
>>> -#define CPU_FEATURE_FSMULD   (1<<  10)
>>> -#define CPU_FEATURE_HYPV     (1<<  11)
>>> -#define CPU_FEATURE_CMT      (1<<  12)
>>> -#define CPU_FEATURE_GL       (1<<  13)
>>> +#define CPU_FEATURE_FLOAT        (1<<  0)
>>> +#define CPU_FEATURE_FLOAT128     (1<<  1)
>>> +#define CPU_FEATURE_SWAP         (1<<  2)
>>> +#define CPU_FEATURE_MUL          (1<<  3)
>>> +#define CPU_FEATURE_DIV          (1<<  4)
>>> +#define CPU_FEATURE_FLUSH        (1<<  5)
>>> +#define CPU_FEATURE_FSQRT        (1<<  6)
>>> +#define CPU_FEATURE_FMUL         (1<<  7)
>>> +#define CPU_FEATURE_VIS1         (1<<  8)
>>> +#define CPU_FEATURE_VIS2         (1<<  9)
>>> +#define CPU_FEATURE_FSMULD       (1<<  10)
>>> +#define CPU_FEATURE_HYPV         (1<<  11)
>>> +#define CPU_FEATURE_CMT          (1<<  12)
>>> +#define CPU_FEATURE_GL           (1<<  13)
>>> +#define CPU_FEATURE_TA0_SHUTDOWN (1<<  14) /* Shutdown on "ta 0x0" */
>>>  #ifndef TARGET_SPARC64
>>>  #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
>>>                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
>>> @@ -436,6 +437,12 @@ typedef struct CPUSPARCState {
>>>  #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
>>>  #endif
>>>     sparc_def_t *def;
>>> +
>>> +    void *irq_manager;
>>> +    void (*qemu_irq_ack) (void *irq_manager, int intno);
>>> +
>>> +    /* Leon3 cache control */
>>> +    uint32_t cache_control;
>>>  } CPUSPARCState;
>>>
>>>  #ifndef NO_CPU_IO_DEFS
>>> @@ -471,6 +478,10 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
>>>  int cpu_cwp_dec(CPUState *env1, int cwp);
>>>  void cpu_set_cwp(CPUState *env1, int new_cwp);
>>>
>>> +void     leon3_cache_control_st(target_ulong addr, uint64_t val, int
>>> size);
>>> +uint64_t leon3_cache_control_ld(target_ulong addr, int size);
>>> +void     leon3_cache_control_int(void);
>>
>> Is there any need to export these?
>>
>
> The last one needs to be exported, the others can be forward declaration in
> op_helper.c.

Could you rearrange the code so that no forward declarations are needed?

>>> +
>>>  /* sun4m.c, sun4u.c */
>>>  void cpu_check_irqs(CPUSPARCState *env);
>>>
>>> diff --git a/target-sparc/helper.c b/target-sparc/helper.c
>>> index e84c312..49bdb58 100644
>>> --- a/target-sparc/helper.c
>>> +++ b/target-sparc/helper.c
>>> @@ -784,6 +784,7 @@ void cpu_reset(CPUSPARCState *env)
>>>     env->pc = 0;
>>>     env->npc = env->pc + 4;
>>>  #endif
>>> +    env->cache_control = 0;
>>>  }
>>>
>>>  static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
>>> @@ -1288,20 +1289,20 @@ static const sparc_def_t sparc_defs[] = {
>>>         .mmu_sfsr_mask = 0xffffffff,
>>>         .mmu_trcr_mask = 0xffffffff,
>>>         .nwindows = 8,
>>> -        .features = CPU_DEFAULT_FEATURES,
>>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>>     },
>>>     {
>>>         .name = "LEON3",
>>>         .iu_version = 0xf3000000,
>>>         .fpu_version = 4<<  17, /* FPU version 4 (Meiko) */
>>>         .mmu_version = 0xf3000000,
>>> -        .mmu_bm = 0x00004000,
>>> +        .mmu_bm = 0x00000000,
>>>         .mmu_ctpr_mask = 0x007ffff0,
>>>         .mmu_cxr_mask = 0x0000003f,
>>>         .mmu_sfsr_mask = 0xffffffff,
>>>         .mmu_trcr_mask = 0xffffffff,
>>>         .nwindows = 8,
>>> -        .features = CPU_DEFAULT_FEATURES,
>>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>>     },
>>>  #endif
>>>  };
>>> diff --git a/target-sparc/helper.h b/target-sparc/helper.h
>>> index 6f103e7..004eaaa 100644
>>> --- a/target-sparc/helper.h
>>> +++ b/target-sparc/helper.h
>>> @@ -83,6 +83,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
>>>  DEF_HELPER_0(fcmpeq_fcc3, void)
>>>  #endif
>>>  DEF_HELPER_1(raise_exception, void, int)
>>> +DEF_HELPER_0(shutdown, void)
>>>  #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
>>>  #define F_HELPER_DQ_0_0(name)                   \
>>>     F_HELPER_0_0(name ## d);                    \
>>> diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
>>> index be3c1e0..0390aec 100644
>>> --- a/target-sparc/op_helper.c
>>> +++ b/target-sparc/op_helper.c
>>> @@ -1,6 +1,7 @@
>>>  #include "exec.h"
>>>  #include "host-utils.h"
>>>  #include "helper.h"
>>> +#include "sysemu.h"
>>>
>>>  //#define DEBUG_MMU
>>>  //#define DEBUG_MXCC
>>> @@ -9,6 +10,7 @@
>>>  //#define DEBUG_ASI
>>>  //#define DEBUG_PCALL
>>>  //#define DEBUG_PSTATE
>>> +//#define DEBUG_CACHE_CONTROL
>>>
>>>  #ifdef DEBUG_MMU
>>>  #define DPRINTF_MMU(fmt, ...)                                   \
>>> @@ -36,6 +38,13 @@
>>>  #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
>>>  #endif
>>>
>>> +#ifdef DEBUG_CACHE_CONTROL
>>> +#define DPRINTF_CACHE_CONTROL(fmt, ...)
>>>   \
>>> +    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
>>> +#else
>>> +#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
>>> +#endif
>>> +
>>>  #ifdef TARGET_SPARC64
>>>  #ifndef TARGET_ABI32
>>>  #define AM_CHECK(env1) ((env1)->pstate&  PS_AM)
>>> @@ -294,6 +303,11 @@ void HELPER(raise_exception)(int tt)
>>>     raise_exception(tt);
>>>  }
>>>
>>> +void helper_shutdown(void)
>>> +{
>>> +    qemu_system_shutdown_request();
>>> +}
>>> +
>>>  void helper_check_align(target_ulong addr, uint32_t align)
>>>  {
>>>     if (addr&  align) {
>>> @@ -1609,8 +1623,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi,
>>> int size, int sign)
>>>
>>>     helper_check_align(addr, size - 1);
>>>     switch (asi) {
>>> -    case 2: /* SuperSparc MXCC registers */
>>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>>         switch (addr) {
>>> +        case 0x00:          /* Leon3 Cache Control */
>>> +        case 0x08:          /* Leon3 Instruction Cache config */
>>> +        case 0x0C:          /* Leon3 Date Cache config */
>>> +            ret = leon3_cache_control_ld(addr, size);
>>> +            break;
>>>         case 0x01c00a00: /* MXCC control register */
>>>             if (size == 8)
>>>                 ret = env->mxccregs[3];
>>> @@ -1838,8 +1857,14 @@ void helper_st_asi(target_ulong addr, uint64_t
>>> val, int asi, int size)
>>>  {
>>>     helper_check_align(addr, size - 1);
>>>     switch(asi) {
>>> -    case 2: /* SuperSparc MXCC registers */
>>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>>         switch (addr) {
>>> +        case 0x00:          /* Leon3 Cache Control */
>>> +        case 0x08:          /* Leon3 Instruction Cache config */
>>> +        case 0x0C:          /* Leon3 Date Cache config */
>>> +            leon3_cache_control_st(addr, val, size);
>>> +            break;
>>> +
>>>         case 0x01c00000: /* MXCC stream data register 0 */
>>>             if (size == 8)
>>>                 env->mxccdata[0] = val;
>>> @@ -4135,6 +4160,13 @@ void do_interrupt(CPUState *env)
>>>     env->pc = env->tbr;
>>>     env->npc = env->pc + 4;
>>>     env->exception_index = -1;
>>> +
>>> +#if !defined(CONFIG_USER_ONLY)
>>> +    /* IRQ acknowledgment */
>>> +    if ((intno&  ~15) == TT_EXTINT&&  env->qemu_irq_ack != NULL) {
>>> +        env->qemu_irq_ack(env->irq_manager, intno);
>>> +    }
>>> +#endif
>>>  }
>>>  #endif
>>>
>>> @@ -4329,3 +4361,118 @@ void helper_tick_set_limit(void *opaque, uint64_t
>>> limit)
>>>  #endif
>>>  }
>>>  #endif
>>> +
>>> +/* Leon3 cache control */
>>> +
>>> +/* Cache control: emulate the behavior of cache control registers but
>>> without
>>> +   any effect on the emulated CPU */
>>> +
>>> +#define CACHE_STATE_MASK 0x3
>>> +#define CACHE_DISABLED   0x0
>>> +#define CACHE_FROZEN     0x1
>>> +#define CACHE_ENABLED    0x3
>>> +
>>> +/* Cache Control register fields */
>>> +
>>> +#define CACHE_CTRL_IF (1<<    4)  /* Instruction Cache Freeze on
>>> Interrupt */
>>> +#define CACHE_CTRL_DF (1<<    5)  /* Data Cache Freeze on Interrupt */
>>> +#define CACHE_CTRL_DP (1<<  14)  /* Data cache flush pending */
>>> +#define CACHE_CTRL_IP (1<<  15)  /* Instruction cache flush pending */
>>> +#define CACHE_CTRL_IB (1<<  16)  /* Instruction burst fetch */
>>> +#define CACHE_CTRL_FI (1<<  21)  /* Flush Instruction cache (Write only)
>>> */
>>> +#define CACHE_CTRL_FD (1<<  22)  /* Flush Data cache (Write only) */
>>> +#define CACHE_CTRL_DS (1<<  23)  /* Data cache snoop enable */
>>
>> These should be at the top of the file.
>>
>
> I just want to put all the cache control code together, it's easier to read.

The actual numerical values are not helpful for understanding the
code. The comments may be, though that may be a sign that the names
could be more self-explanatory.

Patch

diff --git a/Makefile.target b/Makefile.target
index 2800f47..f40e04f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -290,7 +290,10 @@  obj-sparc-y += cirrus_vga.o
 else
 obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
 obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
-obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
+obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
+
+# GRLIB
+obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
 endif
 
 obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
diff --git a/hw/leon3.c b/hw/leon3.c
new file mode 100644
index 0000000..d5fe863
--- /dev/null
+++ b/hw/leon3.c
@@ -0,0 +1,202 @@ 
+/*
+ * QEMU Leon3 System Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+
+#include "grlib.h"
+
+//#define DEBUG_LEON3
+
+#ifdef DEBUG_LEON3
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/* Default system clock.  */
+#define CPU_CLK (40 * 1000 * 1000)
+
+#define PROM_FILENAME        "u-boot.bin"
+
+#define MAX_PILS 16
+
+typedef struct ResetData {
+    CPUState *env;
+    uint64_t  entry;            /* save kernel entry in case of reset */
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    assert(s != NULL);
+    CPUState *env = s->env;
+    assert(env != NULL);
+
+    cpu_reset(env);
+
+    env->halted = 0;
+    env->pc     = s->entry;
+    env->npc    = s->entry + 4;
+}
+
+static void leon3_irq_ack(void *irq_manager, int intno)
+{
+    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
+    leon3_cache_control_int();
+}
+
+static void leon3_generic_hw_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;
+    ram_addr_t  ram_offset, prom_offset;
+    int         ret;
+    char       *filename;
+    qemu_irq   *cpu_irqs = NULL;
+    int         bios_size;
+    int         prom_size;
+    int         aligned_bios_size;
+    ResetData  *reset_info;
+
+    /* Init CPU */
+    if (!cpu_model) {
+        cpu_model = "LEON3";
+    }
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+
+    cpu_sparc_set_id(env, 0);
+
+    /* Reset data */
+    reset_info        = qemu_mallocz(sizeof(ResetData));
+    reset_info->env   = env;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate IRQ manager */
+    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS);
+
+    env->qemu_irq_ack = leon3_irq_ack;
+
+    /* Allocate RAM */
+    if ((uint64_t)ram_size > (1UL << 30)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d, maximum 1G\n",
+                (unsigned int)(ram_size / (1024 * 1024)));
+        exit(1);
+    }
+
+    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
+    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
+
+    /* Allocate BIOS */
+    prom_size = 8 * 1024 * 1024; /* 8Mb */
+    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
+    cpu_register_physical_memory(0x00000000, prom_size,
+                                 prom_offset | IO_MEM_ROM);
+
+    /* Load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    bios_size = get_image_size(filename);
+
+    if (bios_size > prom_size) {
+        fprintf(stderr, "qemu: could not load prom '%s': file too big \n",
+                filename);
+        exit(1);
+    }
+
+    if (bios_size > 0) {
+        aligned_bios_size =
+            (bios_size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+
+        ret = load_image_targphys(filename, 0x00000000, bios_size);
+        if (ret < 0 || ret > prom_size) {
+            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
+            exit(1);
+        }
+    }
+    else if (kernel_filename == NULL) {
+        fprintf(stderr,"Can't read bios image %s\n", filename);
+        exit(1);
+    }
+
+    /* Can directly load an application. */
+    if (kernel_filename != NULL) {
+        long     kernel_size;
+        uint64_t entry;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1 /* big endian */, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        if (bios_size <= 0) {
+            /* If there is no bios/monitor, start the application.  */
+            env->pc = entry;
+            env->npc = entry + 4;
+            reset_info->entry = entry;
+        }
+    }
+
+    /* Allocate timers */
+    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
+
+    /* Allocate uart */
+    if (serial_hds[0]) {
+        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
+    }
+}
+
+QEMUMachine leon3_generic_machine = {
+    .name     = "leon3_generic",
+    .desc     = "Leon-3 generic",
+    .init     = leon3_generic_hw_init,
+    .use_scsi = 0,
+};
+
+static void leon3_machine_init(void)
+{
+    qemu_register_machine(&leon3_generic_machine);
+}
+
+machine_init(leon3_machine_init);
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 7e0d17c..7795be4 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -251,20 +251,21 @@  typedef struct sparc_def_t {
     uint32_t maxtl;
 } sparc_def_t;
 
-#define CPU_FEATURE_FLOAT    (1 << 0)
-#define CPU_FEATURE_FLOAT128 (1 << 1)
-#define CPU_FEATURE_SWAP     (1 << 2)
-#define CPU_FEATURE_MUL      (1 << 3)
-#define CPU_FEATURE_DIV      (1 << 4)
-#define CPU_FEATURE_FLUSH    (1 << 5)
-#define CPU_FEATURE_FSQRT    (1 << 6)
-#define CPU_FEATURE_FMUL     (1 << 7)
-#define CPU_FEATURE_VIS1     (1 << 8)
-#define CPU_FEATURE_VIS2     (1 << 9)
-#define CPU_FEATURE_FSMULD   (1 << 10)
-#define CPU_FEATURE_HYPV     (1 << 11)
-#define CPU_FEATURE_CMT      (1 << 12)
-#define CPU_FEATURE_GL       (1 << 13)
+#define CPU_FEATURE_FLOAT        (1 << 0)
+#define CPU_FEATURE_FLOAT128     (1 << 1)
+#define CPU_FEATURE_SWAP         (1 << 2)
+#define CPU_FEATURE_MUL          (1 << 3)
+#define CPU_FEATURE_DIV          (1 << 4)
+#define CPU_FEATURE_FLUSH        (1 << 5)
+#define CPU_FEATURE_FSQRT        (1 << 6)
+#define CPU_FEATURE_FMUL         (1 << 7)
+#define CPU_FEATURE_VIS1         (1 << 8)
+#define CPU_FEATURE_VIS2         (1 << 9)
+#define CPU_FEATURE_FSMULD       (1 << 10)
+#define CPU_FEATURE_HYPV         (1 << 11)
+#define CPU_FEATURE_CMT          (1 << 12)
+#define CPU_FEATURE_GL           (1 << 13)
+#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
 #ifndef TARGET_SPARC64
 #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
@@ -436,6 +437,12 @@  typedef struct CPUSPARCState {
 #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
 #endif
     sparc_def_t *def;
+
+    void *irq_manager;
+    void (*qemu_irq_ack) (void *irq_manager, int intno);
+
+    /* Leon3 cache control */
+    uint32_t cache_control;
 } CPUSPARCState;
 
 #ifndef NO_CPU_IO_DEFS
@@ -471,6 +478,10 @@  int cpu_cwp_inc(CPUState *env1, int cwp);
 int cpu_cwp_dec(CPUState *env1, int cwp);
 void cpu_set_cwp(CPUState *env1, int new_cwp);
 
+void     leon3_cache_control_st(target_ulong addr, uint64_t val, int size);
+uint64_t leon3_cache_control_ld(target_ulong addr, int size);
+void     leon3_cache_control_int(void);
+
 /* sun4m.c, sun4u.c */
 void cpu_check_irqs(CPUSPARCState *env);
 
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index e84c312..49bdb58 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -784,6 +784,7 @@  void cpu_reset(CPUSPARCState *env)
     env->pc = 0;
     env->npc = env->pc + 4;
 #endif
+    env->cache_control = 0;
 }
 
 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
@@ -1288,20 +1289,20 @@  static const sparc_def_t sparc_defs[] = {
         .mmu_sfsr_mask = 0xffffffff,
         .mmu_trcr_mask = 0xffffffff,
         .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
     },
     {
         .name = "LEON3",
         .iu_version = 0xf3000000,
         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
         .mmu_version = 0xf3000000,
-        .mmu_bm = 0x00004000,
+        .mmu_bm = 0x00000000,
         .mmu_ctpr_mask = 0x007ffff0,
         .mmu_cxr_mask = 0x0000003f,
         .mmu_sfsr_mask = 0xffffffff,
         .mmu_trcr_mask = 0xffffffff,
         .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
     },
 #endif
 };
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 6f103e7..004eaaa 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -83,6 +83,7 @@  DEF_HELPER_0(fcmpeq_fcc2, void)
 DEF_HELPER_0(fcmpeq_fcc3, void)
 #endif
 DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_0(shutdown, void)
 #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
 #define F_HELPER_DQ_0_0(name)                   \
     F_HELPER_0_0(name ## d);                    \
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index be3c1e0..0390aec 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,6 +1,7 @@ 
 #include "exec.h"
 #include "host-utils.h"
 #include "helper.h"
+#include "sysemu.h"
 
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
@@ -9,6 +10,7 @@ 
 //#define DEBUG_ASI
 //#define DEBUG_PCALL
 //#define DEBUG_PSTATE
+//#define DEBUG_CACHE_CONTROL
 
 #ifdef DEBUG_MMU
 #define DPRINTF_MMU(fmt, ...)                                   \
@@ -36,6 +38,13 @@ 
 #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
 #endif
 
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
 #ifdef TARGET_SPARC64
 #ifndef TARGET_ABI32
 #define AM_CHECK(env1) ((env1)->pstate & PS_AM)
@@ -294,6 +303,11 @@  void HELPER(raise_exception)(int tt)
     raise_exception(tt);
 }
 
+void helper_shutdown(void)
+{
+    qemu_system_shutdown_request();
+}
+
 void helper_check_align(target_ulong addr, uint32_t align)
 {
     if (addr & align) {
@@ -1609,8 +1623,13 @@  uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
 
     helper_check_align(addr, size - 1);
     switch (asi) {
-    case 2: /* SuperSparc MXCC registers */
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            ret = leon3_cache_control_ld(addr, size);
+            break;
         case 0x01c00a00: /* MXCC control register */
             if (size == 8)
                 ret = env->mxccregs[3];
@@ -1838,8 +1857,14 @@  void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
 {
     helper_check_align(addr, size - 1);
     switch(asi) {
-    case 2: /* SuperSparc MXCC registers */
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            leon3_cache_control_st(addr, val, size);
+            break;
+
         case 0x01c00000: /* MXCC stream data register 0 */
             if (size == 8)
                 env->mxccdata[0] = val;
@@ -4135,6 +4160,13 @@  void do_interrupt(CPUState *env)
     env->pc = env->tbr;
     env->npc = env->pc + 4;
     env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* IRQ acknowledgment */
+    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+        env->qemu_irq_ack(env->irq_manager, intno);
+    }
+#endif
 }
 #endif
 
@@ -4329,3 +4361,118 @@  void helper_tick_set_limit(void *opaque, uint64_t limit)
 #endif
 }
 #endif
+
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+   any effect on the emulated CPU */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED   0x0
+#define CACHE_FROZEN     0x1
+#define CACHE_ENABLED    0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
+
+
+void leon3_cache_control_int(void)
+{
+    uint32_t state = 0;
+
+    if (env->cache_control & CACHE_CTRL_IF) {
+        /* Instruction cache state */
+        state = env->cache_control & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
+        }
+
+        env->cache_control &= ~CACHE_STATE_MASK;
+        env->cache_control |= state;
+    }
+
+    if (env->cache_control & CACHE_CTRL_DF) {
+        /* Data cache state */
+        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
+        }
+
+        env->cache_control &= ~(CACHE_STATE_MASK << 2);
+        env->cache_control |= (state << 2);
+    }
+}
+
+void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+                          addr, val, size);
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return;
+    }
+
+    switch (addr) {
+        case 0x00:              /* Cache control */
+
+            /* These values must always be read as zeros */
+            val &= ~CACHE_CTRL_FD;
+            val &= ~CACHE_CTRL_FI;
+            val &= ~CACHE_CTRL_IB;
+            val &= ~CACHE_CTRL_IP;
+            val &= ~CACHE_CTRL_DP;
+
+            env->cache_control = val;
+            break;
+        case 0x04:              /* Instruction cache configuration */
+        case 0x08:              /* Data cache configuration */
+            /* Read Only */
+            break;
+        default:
+            DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+            break;
+    };
+}
+
+uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+    uint64_t ret = 0;
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return 0;
+    }
+
+    switch (addr) {
+        case 0x00:              /* Cache control */
+            ret = env->cache_control;
+            break;
+
+            /* Configuration registers are read and only always keep those
+               predefined values */
+
+        case 0x04:              /* Instruction cache configuration */
+            ret = 0x10220000;
+            break;
+        case 0x08:              /* Data cache configuration */
+            ret = 0x18220000;
+            break;
+        default:
+            DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+            break;
+    };
+    DPRINTF_CACHE_CONTROL("st addr:%08x, ret:%" PRIx64 ", size:%d\n",
+                          addr, ret, size);
+    return ret;
+}
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 23f9519..b0e8044 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1997,8 +1997,9 @@  static void disas_sparc_insn(DisasContext * dc)
                     } else
                         tcg_gen_mov_tl(cpu_dst, cpu_src1);
                 }
+
                 cond = GET_FIELD(insn, 3, 6);
-                if (cond == 0x8) {
+                if (cond == 0x8) { /* Trap Always */
                     save_state(dc, cpu_cond);
                     if ((dc->def->features & CPU_FEATURE_HYPV) &&
                         supervisor(dc))
@@ -2007,7 +2008,16 @@  static void disas_sparc_insn(DisasContext * dc)
                         tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
                     tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
                     tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
-                    gen_helper_raise_exception(cpu_tmp32);
+
+                    if (rs2 == 0
+                          &&
+                        dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
+
+                        gen_helper_shutdown();
+
+                    } else {
+                        gen_helper_raise_exception(cpu_tmp32);
+                    }
                 } else if (cond != 0) {
                     TCGv r_cond = tcg_temp_new();
                     int l1;