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