Statistics
| Branch: | Revision:

root / hw / armv7m.c @ cef290b8

History | View | Annotate | Download (7.1 kB)

1 9ee6e8bb pbrook
/*
2 9ee6e8bb pbrook
 * ARMV7M System emulation.
3 9ee6e8bb pbrook
 *
4 9ee6e8bb pbrook
 * Copyright (c) 2006-2007 CodeSourcery.
5 9ee6e8bb pbrook
 * Written by Paul Brook
6 9ee6e8bb pbrook
 *
7 9ee6e8bb pbrook
 * This code is licenced under the GPL.
8 9ee6e8bb pbrook
 */
9 9ee6e8bb pbrook
10 fe7e8758 Paul Brook
#include "sysbus.h"
11 87ecb68b pbrook
#include "arm-misc.h"
12 87ecb68b pbrook
#include "sysemu.h"
13 ca20cf32 Blue Swirl
#include "loader.h"
14 ca20cf32 Blue Swirl
#include "elf.h"
15 9ee6e8bb pbrook
16 9ee6e8bb pbrook
/* Bitbanded IO.  Each word corresponds to a single bit.  */
17 9ee6e8bb pbrook
18 9ee6e8bb pbrook
/* Get the byte address of the real memory for a bitband acess.  */
19 8da3ff18 pbrook
static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
20 9ee6e8bb pbrook
{
21 9ee6e8bb pbrook
    uint32_t res;
22 9ee6e8bb pbrook
23 8da3ff18 pbrook
    res = *(uint32_t *)opaque;
24 9ee6e8bb pbrook
    res |= (addr & 0x1ffffff) >> 5;
25 9ee6e8bb pbrook
    return res;
26 9ee6e8bb pbrook
27 9ee6e8bb pbrook
}
28 9ee6e8bb pbrook
29 c227f099 Anthony Liguori
static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset)
30 9ee6e8bb pbrook
{
31 9ee6e8bb pbrook
    uint8_t v;
32 8da3ff18 pbrook
    cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
33 9ee6e8bb pbrook
    return (v & (1 << ((offset >> 2) & 7))) != 0;
34 9ee6e8bb pbrook
}
35 9ee6e8bb pbrook
36 c227f099 Anthony Liguori
static void bitband_writeb(void *opaque, target_phys_addr_t offset,
37 9ee6e8bb pbrook
                           uint32_t value)
38 9ee6e8bb pbrook
{
39 9ee6e8bb pbrook
    uint32_t addr;
40 9ee6e8bb pbrook
    uint8_t mask;
41 9ee6e8bb pbrook
    uint8_t v;
42 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset);
43 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 7));
44 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, &v, 1);
45 9ee6e8bb pbrook
    if (value & 1)
46 9ee6e8bb pbrook
        v |= mask;
47 9ee6e8bb pbrook
    else
48 9ee6e8bb pbrook
        v &= ~mask;
49 9ee6e8bb pbrook
    cpu_physical_memory_write(addr, &v, 1);
50 9ee6e8bb pbrook
}
51 9ee6e8bb pbrook
52 c227f099 Anthony Liguori
static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset)
53 9ee6e8bb pbrook
{
54 9ee6e8bb pbrook
    uint32_t addr;
55 9ee6e8bb pbrook
    uint16_t mask;
56 9ee6e8bb pbrook
    uint16_t v;
57 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~1;
58 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 15));
59 9ee6e8bb pbrook
    mask = tswap16(mask);
60 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
61 9ee6e8bb pbrook
    return (v & mask) != 0;
62 9ee6e8bb pbrook
}
63 9ee6e8bb pbrook
64 c227f099 Anthony Liguori
static void bitband_writew(void *opaque, target_phys_addr_t offset,
65 9ee6e8bb pbrook
                           uint32_t value)
66 9ee6e8bb pbrook
{
67 9ee6e8bb pbrook
    uint32_t addr;
68 9ee6e8bb pbrook
    uint16_t mask;
69 9ee6e8bb pbrook
    uint16_t v;
70 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~1;
71 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 15));
72 9ee6e8bb pbrook
    mask = tswap16(mask);
73 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
74 9ee6e8bb pbrook
    if (value & 1)
75 9ee6e8bb pbrook
        v |= mask;
76 9ee6e8bb pbrook
    else
77 9ee6e8bb pbrook
        v &= ~mask;
78 9ee6e8bb pbrook
    cpu_physical_memory_write(addr, (uint8_t *)&v, 2);
79 9ee6e8bb pbrook
}
80 9ee6e8bb pbrook
81 c227f099 Anthony Liguori
static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset)
82 9ee6e8bb pbrook
{
83 9ee6e8bb pbrook
    uint32_t addr;
84 9ee6e8bb pbrook
    uint32_t mask;
85 9ee6e8bb pbrook
    uint32_t v;
86 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~3;
87 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 31));
88 9ee6e8bb pbrook
    mask = tswap32(mask);
89 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
90 9ee6e8bb pbrook
    return (v & mask) != 0;
91 9ee6e8bb pbrook
}
92 9ee6e8bb pbrook
93 c227f099 Anthony Liguori
static void bitband_writel(void *opaque, target_phys_addr_t offset,
94 9ee6e8bb pbrook
                           uint32_t value)
95 9ee6e8bb pbrook
{
96 9ee6e8bb pbrook
    uint32_t addr;
97 9ee6e8bb pbrook
    uint32_t mask;
98 9ee6e8bb pbrook
    uint32_t v;
99 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~3;
100 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 31));
101 9ee6e8bb pbrook
    mask = tswap32(mask);
102 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
103 9ee6e8bb pbrook
    if (value & 1)
104 9ee6e8bb pbrook
        v |= mask;
105 9ee6e8bb pbrook
    else
106 9ee6e8bb pbrook
        v &= ~mask;
107 9ee6e8bb pbrook
    cpu_physical_memory_write(addr, (uint8_t *)&v, 4);
108 9ee6e8bb pbrook
}
109 9ee6e8bb pbrook
110 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const bitband_readfn[] = {
111 9ee6e8bb pbrook
   bitband_readb,
112 9ee6e8bb pbrook
   bitband_readw,
113 9ee6e8bb pbrook
   bitband_readl
114 9ee6e8bb pbrook
};
115 9ee6e8bb pbrook
116 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const bitband_writefn[] = {
117 9ee6e8bb pbrook
   bitband_writeb,
118 9ee6e8bb pbrook
   bitband_writew,
119 9ee6e8bb pbrook
   bitband_writel
120 9ee6e8bb pbrook
};
121 9ee6e8bb pbrook
122 40905a6a Paul Brook
typedef struct {
123 40905a6a Paul Brook
    SysBusDevice busdev;
124 40905a6a Paul Brook
    uint32_t base;
125 40905a6a Paul Brook
} BitBandState;
126 40905a6a Paul Brook
127 81a322d4 Gerd Hoffmann
static int bitband_init(SysBusDevice *dev)
128 9ee6e8bb pbrook
{
129 40905a6a Paul Brook
    BitBandState *s = FROM_SYSBUS(BitBandState, dev);
130 9ee6e8bb pbrook
    int iomemtype;
131 9ee6e8bb pbrook
132 1eed09cb Avi Kivity
    iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn,
133 40905a6a Paul Brook
                                       &s->base);
134 40905a6a Paul Brook
    sysbus_init_mmio(dev, 0x02000000, iomemtype);
135 81a322d4 Gerd Hoffmann
    return 0;
136 40905a6a Paul Brook
}
137 40905a6a Paul Brook
138 40905a6a Paul Brook
static void armv7m_bitband_init(void)
139 40905a6a Paul Brook
{
140 40905a6a Paul Brook
    DeviceState *dev;
141 40905a6a Paul Brook
142 40905a6a Paul Brook
    dev = qdev_create(NULL, "ARM,bitband-memory");
143 ee6847d1 Gerd Hoffmann
    qdev_prop_set_uint32(dev, "base", 0x20000000);
144 e23a1b33 Markus Armbruster
    qdev_init_nofail(dev);
145 40905a6a Paul Brook
    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
146 40905a6a Paul Brook
147 40905a6a Paul Brook
    dev = qdev_create(NULL, "ARM,bitband-memory");
148 ee6847d1 Gerd Hoffmann
    qdev_prop_set_uint32(dev, "base", 0x40000000);
149 e23a1b33 Markus Armbruster
    qdev_init_nofail(dev);
150 40905a6a Paul Brook
    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
151 9ee6e8bb pbrook
}
152 9ee6e8bb pbrook
153 9ee6e8bb pbrook
/* Board init.  */
154 9ee6e8bb pbrook
/* Init CPU and memory for a v7-M based board.
155 9ee6e8bb pbrook
   flash_size and sram_size are in kb.
156 9ee6e8bb pbrook
   Returns the NVIC array.  */
157 9ee6e8bb pbrook
158 9ee6e8bb pbrook
qemu_irq *armv7m_init(int flash_size, int sram_size,
159 9ee6e8bb pbrook
                      const char *kernel_filename, const char *cpu_model)
160 9ee6e8bb pbrook
{
161 9ee6e8bb pbrook
    CPUState *env;
162 fe7e8758 Paul Brook
    DeviceState *nvic;
163 fe7e8758 Paul Brook
    /* FIXME: make this local state.  */
164 fe7e8758 Paul Brook
    static qemu_irq pic[64];
165 fe7e8758 Paul Brook
    qemu_irq *cpu_pic;
166 9ee6e8bb pbrook
    uint32_t pc;
167 9ee6e8bb pbrook
    int image_size;
168 9ee6e8bb pbrook
    uint64_t entry;
169 9ee6e8bb pbrook
    uint64_t lowaddr;
170 fe7e8758 Paul Brook
    int i;
171 ca20cf32 Blue Swirl
    int big_endian;
172 9ee6e8bb pbrook
173 9ee6e8bb pbrook
    flash_size *= 1024;
174 9ee6e8bb pbrook
    sram_size *= 1024;
175 9ee6e8bb pbrook
176 9ee6e8bb pbrook
    if (!cpu_model)
177 9ee6e8bb pbrook
        cpu_model = "cortex-m3";
178 9ee6e8bb pbrook
    env = cpu_init(cpu_model);
179 9ee6e8bb pbrook
    if (!env) {
180 9ee6e8bb pbrook
        fprintf(stderr, "Unable to find CPU definition\n");
181 9ee6e8bb pbrook
        exit(1);
182 9ee6e8bb pbrook
    }
183 9ee6e8bb pbrook
184 9ee6e8bb pbrook
#if 0
185 9ee6e8bb pbrook
    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
186 9ee6e8bb pbrook
       We don't have proper commandline options, so allocate half of memory
187 9ee6e8bb pbrook
       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
188 9ee6e8bb pbrook
    if (ram_size > (512 + 32) * 1024 * 1024)
189 9ee6e8bb pbrook
        ram_size = (512 + 32) * 1024 * 1024;
190 9ee6e8bb pbrook
    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
191 9ee6e8bb pbrook
    if (sram_size > 32 * 1024 * 1024)
192 9ee6e8bb pbrook
        sram_size = 32 * 1024 * 1024;
193 9ee6e8bb pbrook
    code_size = ram_size - sram_size;
194 9ee6e8bb pbrook
#endif
195 9ee6e8bb pbrook
196 9ee6e8bb pbrook
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
197 dcac9679 pbrook
    cpu_register_physical_memory(0, flash_size,
198 dcac9679 pbrook
                                 qemu_ram_alloc(flash_size) | IO_MEM_ROM);
199 9ee6e8bb pbrook
    cpu_register_physical_memory(0x20000000, sram_size,
200 dcac9679 pbrook
                                 qemu_ram_alloc(sram_size) | IO_MEM_RAM);
201 9ee6e8bb pbrook
    armv7m_bitband_init();
202 9ee6e8bb pbrook
203 fe7e8758 Paul Brook
    nvic = qdev_create(NULL, "armv7m_nvic");
204 bdb11366 Paul Brook
    env->v7m.nvic = nvic;
205 e23a1b33 Markus Armbruster
    qdev_init_nofail(nvic);
206 fe7e8758 Paul Brook
    cpu_pic = arm_pic_init_cpu(env);
207 fe7e8758 Paul Brook
    sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
208 fe7e8758 Paul Brook
    for (i = 0; i < 64; i++) {
209 067a3ddc Paul Brook
        pic[i] = qdev_get_gpio_in(nvic, i);
210 fe7e8758 Paul Brook
    }
211 9ee6e8bb pbrook
212 ca20cf32 Blue Swirl
#ifdef TARGET_WORDS_BIGENDIAN
213 ca20cf32 Blue Swirl
    big_endian = 1;
214 ca20cf32 Blue Swirl
#else
215 ca20cf32 Blue Swirl
    big_endian = 0;
216 ca20cf32 Blue Swirl
#endif
217 ca20cf32 Blue Swirl
218 ca20cf32 Blue Swirl
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL,
219 ca20cf32 Blue Swirl
                          big_endian, ELF_MACHINE, 1);
220 9ee6e8bb pbrook
    if (image_size < 0) {
221 dcac9679 pbrook
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
222 9ee6e8bb pbrook
        lowaddr = 0;
223 9ee6e8bb pbrook
    }
224 9ee6e8bb pbrook
    if (image_size < 0) {
225 9ee6e8bb pbrook
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
226 9ee6e8bb pbrook
                kernel_filename);
227 9ee6e8bb pbrook
        exit(1);
228 9ee6e8bb pbrook
    }
229 9ee6e8bb pbrook
230 9ee6e8bb pbrook
    /* If the image was loaded at address zero then assume it is a
231 9ee6e8bb pbrook
       regular ROM image and perform the normal CPU reset sequence.
232 9ee6e8bb pbrook
       Otherwise jump directly to the entry point.  */
233 9ee6e8bb pbrook
    if (lowaddr == 0) {
234 44654490 pbrook
        env->regs[13] = ldl_phys(0);
235 44654490 pbrook
        pc = ldl_phys(4);
236 9ee6e8bb pbrook
    } else {
237 9ee6e8bb pbrook
        pc = entry;
238 9ee6e8bb pbrook
    }
239 9ee6e8bb pbrook
    env->thumb = pc & 1;
240 9ee6e8bb pbrook
    env->regs[15] = pc & ~1;
241 9ee6e8bb pbrook
242 9ee6e8bb pbrook
    /* Hack to map an additional page of ram at the top of the address
243 9ee6e8bb pbrook
       space.  This stops qemu complaining about executing code outside RAM
244 9ee6e8bb pbrook
       when returning from an exception.  */
245 dcac9679 pbrook
    cpu_register_physical_memory(0xfffff000, 0x1000,
246 dcac9679 pbrook
                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
247 9ee6e8bb pbrook
248 9ee6e8bb pbrook
    return pic;
249 9ee6e8bb pbrook
}
250 40905a6a Paul Brook
251 ee6847d1 Gerd Hoffmann
static SysBusDeviceInfo bitband_info = {
252 ee6847d1 Gerd Hoffmann
    .init = bitband_init,
253 ee6847d1 Gerd Hoffmann
    .qdev.name  = "ARM,bitband-memory",
254 ee6847d1 Gerd Hoffmann
    .qdev.size  = sizeof(BitBandState),
255 ee6847d1 Gerd Hoffmann
    .qdev.props = (Property[]) {
256 1832efa2 Gerd Hoffmann
        DEFINE_PROP_UINT32("base", BitBandState, base, 0),
257 1832efa2 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
258 ee6847d1 Gerd Hoffmann
    }
259 ee6847d1 Gerd Hoffmann
};
260 ee6847d1 Gerd Hoffmann
261 40905a6a Paul Brook
static void armv7m_register_devices(void)
262 40905a6a Paul Brook
{
263 ee6847d1 Gerd Hoffmann
    sysbus_register_withprop(&bitband_info);
264 40905a6a Paul Brook
}
265 40905a6a Paul Brook
266 40905a6a Paul Brook
device_init(armv7m_register_devices)