Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 313feaab

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