symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/armv7m.c
author johnathan.white@2718R8BGH51.accenture.com
Mon, 08 Mar 2010 18:45:03 +0000
changeset 46 b6935a90ca64
parent 1 2fb8b9db1c86
permissions -rw-r--r--
Modify framebuffer and NGA framebuffer to read screen size from board model dtb file. Optimise memory usuage of frame buffer Add example minigui application with hooks to profiler (which writes results to S:\). Modified NGA framebuffer to run its own dfc queue at high priority

/*
 * ARMV7M System emulation.
 *
 * Copyright (c) 2006-2007 CodeSourcery.
 * Written by Paul Brook
 *
 * This code is licenced under the GPL.
 */

#include "hw.h"
#include "arm-misc.h"
#include "sysemu.h"

/* Bitbanded IO.  Each word corresponds to a single bit.  */

/* Get the byte address of the real memory for a bitband acess.  */
static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
{
    uint32_t res;

    res = *(uint32_t *)opaque;
    res |= (addr & 0x1ffffff) >> 5;
    return res;

}

static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset)
{
    uint8_t v;
    cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
    return (v & (1 << ((offset >> 2) & 7))) != 0;
}

static void bitband_writeb(void *opaque, target_phys_addr_t offset,
                           uint32_t value)
{
    uint32_t addr;
    uint8_t mask;
    uint8_t v;
    addr = bitband_addr(opaque, offset);
    mask = (1 << ((offset >> 2) & 7));
    cpu_physical_memory_read(addr, &v, 1);
    if (value & 1)
        v |= mask;
    else
        v &= ~mask;
    cpu_physical_memory_write(addr, &v, 1);
}

static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset)
{
    uint32_t addr;
    uint16_t mask;
    uint16_t v;
    addr = bitband_addr(opaque, offset) & ~1;
    mask = (1 << ((offset >> 2) & 15));
    mask = tswap16(mask);
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
    return (v & mask) != 0;
}

static void bitband_writew(void *opaque, target_phys_addr_t offset,
                           uint32_t value)
{
    uint32_t addr;
    uint16_t mask;
    uint16_t v;
    addr = bitband_addr(opaque, offset) & ~1;
    mask = (1 << ((offset >> 2) & 15));
    mask = tswap16(mask);
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
    if (value & 1)
        v |= mask;
    else
        v &= ~mask;
    cpu_physical_memory_write(addr, (uint8_t *)&v, 2);
}

static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset)
{
    uint32_t addr;
    uint32_t mask;
    uint32_t v;
    addr = bitband_addr(opaque, offset) & ~3;
    mask = (1 << ((offset >> 2) & 31));
    mask = tswap32(mask);
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
    return (v & mask) != 0;
}

static void bitband_writel(void *opaque, target_phys_addr_t offset,
                           uint32_t value)
{
    uint32_t addr;
    uint32_t mask;
    uint32_t v;
    addr = bitband_addr(opaque, offset) & ~3;
    mask = (1 << ((offset >> 2) & 31));
    mask = tswap32(mask);
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
    if (value & 1)
        v |= mask;
    else
        v &= ~mask;
    cpu_physical_memory_write(addr, (uint8_t *)&v, 4);
}

static CPUReadMemoryFunc *bitband_readfn[] = {
   bitband_readb,
   bitband_readw,
   bitband_readl
};

static CPUWriteMemoryFunc *bitband_writefn[] = {
   bitband_writeb,
   bitband_writew,
   bitband_writel
};

static void armv7m_bitband_init(void)
{
    int iomemtype;
    static uint32_t bitband1_offset = 0x20000000;
    static uint32_t bitband2_offset = 0x40000000;

    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
                                       &bitband1_offset);
    cpu_register_physical_memory(0x22000000, 0x02000000, iomemtype);
    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
                                       &bitband2_offset);
    cpu_register_physical_memory(0x42000000, 0x02000000, iomemtype);
}

/* Board init.  */
/* Init CPU and memory for a v7-M based board.
   flash_size and sram_size are in kb.
   Returns the NVIC array.  */

qemu_irq *armv7m_init(int flash_size, int sram_size,
                      const char *kernel_filename, const char *cpu_model)
{
    CPUState *env;
    qemu_irq *pic;
    uint32_t pc;
    int image_size;
    uint64_t entry;
    uint64_t lowaddr;

    flash_size *= 1024;
    sram_size *= 1024;

    if (!cpu_model)
	cpu_model = "cortex-m3";
    env = cpu_init(cpu_model);
    if (!env) {
        fprintf(stderr, "Unable to find CPU definition\n");
        exit(1);
    }

#if 0
    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
       We don't have proper commandline options, so allocate half of memory
       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
    if (ram_size > (512 + 32) * 1024 * 1024)
        ram_size = (512 + 32) * 1024 * 1024;
    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
    if (sram_size > 32 * 1024 * 1024)
        sram_size = 32 * 1024 * 1024;
    code_size = ram_size - sram_size;
#endif

    /* Flash programming is done via the SCU, so pretend it is ROM.  */
    cpu_register_physical_memory(0, flash_size, IO_MEM_ROM);
    cpu_register_physical_memory(0x20000000, sram_size,
                                 flash_size + IO_MEM_RAM);
    armv7m_bitband_init();

    pic = armv7m_nvic_init(env);

    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
    if (image_size < 0) {
        /* FIXME: This is broken if it spans multiple regions.  */
        image_size = load_image(kernel_filename, host_ram_addr(0));
	lowaddr = 0;
    }
    if (image_size < 0) {
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
                kernel_filename);
        exit(1);
    }

    /* If the image was loaded at address zero then assume it is a
       regular ROM image and perform the normal CPU reset sequence.
       Otherwise jump directly to the entry point.  */
    if (lowaddr == 0) {
	env->regs[13] = ldl_phys(0);
	pc = ldl_phys(4);
    } else {
	pc = entry;
    }
    env->thumb = pc & 1;
    env->regs[15] = pc & ~1;

    /* Hack to map an additional page of ram at the top of the address
       space.  This stops qemu complaining about executing code outside RAM
       when returning from an exception.  */
    cpu_register_physical_memory(0xfffff000, 0x1000, IO_MEM_RAM + ram_size);

    return pic;
}