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