Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 19d110ab

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