]> git.proxmox.com Git - qemu.git/blame - hw/arm/armv7m.c
microdrive: Coding Style cleanups
[qemu.git] / hw / arm / armv7m.c
CommitLineData
9ee6e8bb
PB
1/*
2 * ARMV7M System emulation.
3 *
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
6 *
2167f7bc 7 * This code is licensed under the GPL.
9ee6e8bb
PB
8 */
9
83c9f4ca 10#include "hw/sysbus.h"
bd2be150 11#include "hw/arm/arm.h"
83c9f4ca 12#include "hw/loader.h"
ca20cf32 13#include "elf.h"
5633b90a
AF
14#include "sysemu/qtest.h"
15#include "qemu/error-report.h"
9ee6e8bb
PB
16
17/* Bitbanded IO. Each word corresponds to a single bit. */
18
2167f7bc 19/* Get the byte address of the real memory for a bitband access. */
8da3ff18 20static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
9ee6e8bb
PB
21{
22 uint32_t res;
23
8da3ff18 24 res = *(uint32_t *)opaque;
9ee6e8bb
PB
25 res |= (addr & 0x1ffffff) >> 5;
26 return res;
27
28}
29
a8170e5e 30static uint32_t bitband_readb(void *opaque, hwaddr offset)
9ee6e8bb
PB
31{
32 uint8_t v;
8da3ff18 33 cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
9ee6e8bb
PB
34 return (v & (1 << ((offset >> 2) & 7))) != 0;
35}
36
a8170e5e 37static void bitband_writeb(void *opaque, hwaddr offset,
9ee6e8bb
PB
38 uint32_t value)
39{
40 uint32_t addr;
41 uint8_t mask;
42 uint8_t v;
8da3ff18 43 addr = bitband_addr(opaque, offset);
9ee6e8bb
PB
44 mask = (1 << ((offset >> 2) & 7));
45 cpu_physical_memory_read(addr, &v, 1);
46 if (value & 1)
47 v |= mask;
48 else
49 v &= ~mask;
50 cpu_physical_memory_write(addr, &v, 1);
51}
52
a8170e5e 53static uint32_t bitband_readw(void *opaque, hwaddr offset)
9ee6e8bb
PB
54{
55 uint32_t addr;
56 uint16_t mask;
57 uint16_t v;
8da3ff18 58 addr = bitband_addr(opaque, offset) & ~1;
9ee6e8bb
PB
59 mask = (1 << ((offset >> 2) & 15));
60 mask = tswap16(mask);
e1fe50dc 61 cpu_physical_memory_read(addr, &v, 2);
9ee6e8bb
PB
62 return (v & mask) != 0;
63}
64
a8170e5e 65static void bitband_writew(void *opaque, hwaddr offset,
9ee6e8bb
PB
66 uint32_t value)
67{
68 uint32_t addr;
69 uint16_t mask;
70 uint16_t v;
8da3ff18 71 addr = bitband_addr(opaque, offset) & ~1;
9ee6e8bb
PB
72 mask = (1 << ((offset >> 2) & 15));
73 mask = tswap16(mask);
e1fe50dc 74 cpu_physical_memory_read(addr, &v, 2);
9ee6e8bb
PB
75 if (value & 1)
76 v |= mask;
77 else
78 v &= ~mask;
e1fe50dc 79 cpu_physical_memory_write(addr, &v, 2);
9ee6e8bb
PB
80}
81
a8170e5e 82static uint32_t bitband_readl(void *opaque, hwaddr offset)
9ee6e8bb
PB
83{
84 uint32_t addr;
85 uint32_t mask;
86 uint32_t v;
8da3ff18 87 addr = bitband_addr(opaque, offset) & ~3;
9ee6e8bb
PB
88 mask = (1 << ((offset >> 2) & 31));
89 mask = tswap32(mask);
e1fe50dc 90 cpu_physical_memory_read(addr, &v, 4);
9ee6e8bb
PB
91 return (v & mask) != 0;
92}
93
a8170e5e 94static void bitband_writel(void *opaque, hwaddr offset,
9ee6e8bb
PB
95 uint32_t value)
96{
97 uint32_t addr;
98 uint32_t mask;
99 uint32_t v;
8da3ff18 100 addr = bitband_addr(opaque, offset) & ~3;
9ee6e8bb
PB
101 mask = (1 << ((offset >> 2) & 31));
102 mask = tswap32(mask);
e1fe50dc 103 cpu_physical_memory_read(addr, &v, 4);
9ee6e8bb
PB
104 if (value & 1)
105 v |= mask;
106 else
107 v &= ~mask;
e1fe50dc 108 cpu_physical_memory_write(addr, &v, 4);
9ee6e8bb
PB
109}
110
f69bf9d4
AK
111static const MemoryRegionOps bitband_ops = {
112 .old_mmio = {
113 .read = { bitband_readb, bitband_readw, bitband_readl, },
114 .write = { bitband_writeb, bitband_writew, bitband_writel, },
115 },
116 .endianness = DEVICE_NATIVE_ENDIAN,
9ee6e8bb
PB
117};
118
936230a7
AF
119#define TYPE_BITBAND "ARM,bitband-memory"
120#define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND)
121
40905a6a 122typedef struct {
936230a7
AF
123 /*< private >*/
124 SysBusDevice parent_obj;
125 /*< public >*/
126
f69bf9d4 127 MemoryRegion iomem;
40905a6a
PB
128 uint32_t base;
129} BitBandState;
130
81a322d4 131static int bitband_init(SysBusDevice *dev)
9ee6e8bb 132{
936230a7 133 BitBandState *s = BITBAND(dev);
9ee6e8bb 134
64bde0f3
PB
135 memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base,
136 "bitband", 0x02000000);
750ecd44 137 sysbus_init_mmio(dev, &s->iomem);
81a322d4 138 return 0;
40905a6a
PB
139}
140
141static void armv7m_bitband_init(void)
142{
143 DeviceState *dev;
144
936230a7 145 dev = qdev_create(NULL, TYPE_BITBAND);
ee6847d1 146 qdev_prop_set_uint32(dev, "base", 0x20000000);
e23a1b33 147 qdev_init_nofail(dev);
1356b98d 148 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000);
40905a6a 149
936230a7 150 dev = qdev_create(NULL, TYPE_BITBAND);
ee6847d1 151 qdev_prop_set_uint32(dev, "base", 0x40000000);
e23a1b33 152 qdev_init_nofail(dev);
1356b98d 153 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000);
9ee6e8bb
PB
154}
155
156/* Board init. */
983fe826
PB
157
158static void armv7m_reset(void *opaque)
159{
31363f12
AF
160 ARMCPU *cpu = opaque;
161
162 cpu_reset(CPU(cpu));
983fe826
PB
163}
164
9ee6e8bb
PB
165/* Init CPU and memory for a v7-M based board.
166 flash_size and sram_size are in kb.
167 Returns the NVIC array. */
168
7d6f78cf
AK
169qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
170 int flash_size, int sram_size,
9ee6e8bb
PB
171 const char *kernel_filename, const char *cpu_model)
172{
0f37c99b 173 ARMCPU *cpu;
5ae93306 174 CPUARMState *env;
fe7e8758
PB
175 DeviceState *nvic;
176 /* FIXME: make this local state. */
177 static qemu_irq pic[64];
9ee6e8bb
PB
178 int image_size;
179 uint64_t entry;
180 uint64_t lowaddr;
fe7e8758 181 int i;
ca20cf32 182 int big_endian;
7d6f78cf
AK
183 MemoryRegion *sram = g_new(MemoryRegion, 1);
184 MemoryRegion *flash = g_new(MemoryRegion, 1);
185 MemoryRegion *hack = g_new(MemoryRegion, 1);
9ee6e8bb
PB
186
187 flash_size *= 1024;
188 sram_size *= 1024;
189
0f37c99b 190 if (cpu_model == NULL) {
9ee6e8bb 191 cpu_model = "cortex-m3";
0f37c99b
AF
192 }
193 cpu = cpu_arm_init(cpu_model);
194 if (cpu == NULL) {
9ee6e8bb
PB
195 fprintf(stderr, "Unable to find CPU definition\n");
196 exit(1);
197 }
0f37c99b 198 env = &cpu->env;
9ee6e8bb
PB
199
200#if 0
201 /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
202 We don't have proper commandline options, so allocate half of memory
203 as SRAM, up to a maximum of 32Mb, and the rest as code. */
204 if (ram_size > (512 + 32) * 1024 * 1024)
205 ram_size = (512 + 32) * 1024 * 1024;
206 sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
207 if (sram_size > 32 * 1024 * 1024)
208 sram_size = 32 * 1024 * 1024;
209 code_size = ram_size - sram_size;
210#endif
211
212 /* Flash programming is done via the SCU, so pretend it is ROM. */
2c9b15ca 213 memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size);
c5705a77 214 vmstate_register_ram_global(flash);
7d6f78cf
AK
215 memory_region_set_readonly(flash, true);
216 memory_region_add_subregion(address_space_mem, 0, flash);
2c9b15ca 217 memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size);
c5705a77 218 vmstate_register_ram_global(sram);
7d6f78cf 219 memory_region_add_subregion(address_space_mem, 0x20000000, sram);
9ee6e8bb
PB
220 armv7m_bitband_init();
221
fe7e8758 222 nvic = qdev_create(NULL, "armv7m_nvic");
983fe826 223 env->nvic = nvic;
e23a1b33 224 qdev_init_nofail(nvic);
de3a658f
PM
225 sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0,
226 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
fe7e8758 227 for (i = 0; i < 64; i++) {
067a3ddc 228 pic[i] = qdev_get_gpio_in(nvic, i);
fe7e8758 229 }
9ee6e8bb 230
ca20cf32
BS
231#ifdef TARGET_WORDS_BIGENDIAN
232 big_endian = 1;
233#else
234 big_endian = 0;
235#endif
236
5633b90a 237 if (!kernel_filename && !qtest_enabled()) {
01fd41ab
PC
238 fprintf(stderr, "Guest image must be specified (using -kernel)\n");
239 exit(1);
240 }
241
5633b90a
AF
242 if (kernel_filename) {
243 image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
244 NULL, big_endian, ELF_MACHINE, 1);
245 if (image_size < 0) {
246 image_size = load_image_targphys(kernel_filename, 0, flash_size);
247 lowaddr = 0;
248 }
249 if (image_size < 0) {
250 error_report("Could not load kernel '%s'", kernel_filename);
251 exit(1);
252 }
9ee6e8bb
PB
253 }
254
9ee6e8bb
PB
255 /* Hack to map an additional page of ram at the top of the address
256 space. This stops qemu complaining about executing code outside RAM
257 when returning from an exception. */
2c9b15ca 258 memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000);
c5705a77 259 vmstate_register_ram_global(hack);
7d6f78cf 260 memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
9ee6e8bb 261
31363f12 262 qemu_register_reset(armv7m_reset, cpu);
9ee6e8bb
PB
263 return pic;
264}
40905a6a 265
999e12bb
AL
266static Property bitband_properties[] = {
267 DEFINE_PROP_UINT32("base", BitBandState, base, 0),
268 DEFINE_PROP_END_OF_LIST(),
269};
270
271static void bitband_class_init(ObjectClass *klass, void *data)
272{
39bffca2 273 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb
AL
274 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
275
276 k->init = bitband_init;
39bffca2 277 dc->props = bitband_properties;
999e12bb
AL
278}
279
8c43a6f0 280static const TypeInfo bitband_info = {
936230a7 281 .name = TYPE_BITBAND,
39bffca2
AL
282 .parent = TYPE_SYS_BUS_DEVICE,
283 .instance_size = sizeof(BitBandState),
284 .class_init = bitband_class_init,
ee6847d1
GH
285};
286
83f7d43a 287static void armv7m_register_types(void)
40905a6a 288{
39bffca2 289 type_register_static(&bitband_info);
40905a6a
PB
290}
291
83f7d43a 292type_init(armv7m_register_types)