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