]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - hw/armv7m.c
5c7a9502c6c95e596ba2b6bf876921dfb3b348ee
[lisovros/qemu_apohw.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 const MemoryRegionOps bitband_ops = {
110     .old_mmio = {
111         .read = { bitband_readb, bitband_readw, bitband_readl, },
112         .write = { bitband_writeb, bitband_writew, bitband_writel, },
113     },
114     .endianness = DEVICE_NATIVE_ENDIAN,
115 };
116
117 typedef struct {
118     SysBusDevice busdev;
119     MemoryRegion iomem;
120     uint32_t base;
121 } BitBandState;
122
123 static int bitband_init(SysBusDevice *dev)
124 {
125     BitBandState *s = FROM_SYSBUS(BitBandState, dev);
126
127     memory_region_init_io(&s->iomem, &bitband_ops, &s->base, "bitband",
128                           0x02000000);
129     sysbus_init_mmio(dev, &s->iomem);
130     return 0;
131 }
132
133 static void armv7m_bitband_init(void)
134 {
135     DeviceState *dev;
136
137     dev = qdev_create(NULL, "ARM,bitband-memory");
138     qdev_prop_set_uint32(dev, "base", 0x20000000);
139     qdev_init_nofail(dev);
140     sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
141
142     dev = qdev_create(NULL, "ARM,bitband-memory");
143     qdev_prop_set_uint32(dev, "base", 0x40000000);
144     qdev_init_nofail(dev);
145     sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
146 }
147
148 /* Board init.  */
149
150 static void armv7m_reset(void *opaque)
151 {
152     cpu_reset((CPUState *)opaque);
153 }
154
155 /* Init CPU and memory for a v7-M based board.
156    flash_size and sram_size are in kb.
157    Returns the NVIC array.  */
158
159 qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
160                       int flash_size, int sram_size,
161                       const char *kernel_filename, const char *cpu_model)
162 {
163     CPUState *env;
164     DeviceState *nvic;
165     /* FIXME: make this local state.  */
166     static qemu_irq pic[64];
167     qemu_irq *cpu_pic;
168     int image_size;
169     uint64_t entry;
170     uint64_t lowaddr;
171     int i;
172     int big_endian;
173     MemoryRegion *sram = g_new(MemoryRegion, 1);
174     MemoryRegion *flash = g_new(MemoryRegion, 1);
175     MemoryRegion *hack = g_new(MemoryRegion, 1);
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     memory_region_init_ram(flash, "armv7m.flash", flash_size);
202     vmstate_register_ram_global(flash);
203     memory_region_set_readonly(flash, true);
204     memory_region_add_subregion(address_space_mem, 0, flash);
205     memory_region_init_ram(sram, "armv7m.sram", sram_size);
206     vmstate_register_ram_global(sram);
207     memory_region_add_subregion(address_space_mem, 0x20000000, sram);
208     armv7m_bitband_init();
209
210     nvic = qdev_create(NULL, "armv7m_nvic");
211     env->nvic = nvic;
212     qdev_init_nofail(nvic);
213     cpu_pic = arm_pic_init_cpu(env);
214     sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
215     for (i = 0; i < 64; i++) {
216         pic[i] = qdev_get_gpio_in(nvic, i);
217     }
218
219 #ifdef TARGET_WORDS_BIGENDIAN
220     big_endian = 1;
221 #else
222     big_endian = 0;
223 #endif
224
225     image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
226                           NULL, big_endian, ELF_MACHINE, 1);
227     if (image_size < 0) {
228         image_size = load_image_targphys(kernel_filename, 0, flash_size);
229         lowaddr = 0;
230     }
231     if (image_size < 0) {
232         fprintf(stderr, "qemu: could not load kernel '%s'\n",
233                 kernel_filename);
234         exit(1);
235     }
236
237     /* Hack to map an additional page of ram at the top of the address
238        space.  This stops qemu complaining about executing code outside RAM
239        when returning from an exception.  */
240     memory_region_init_ram(hack, "armv7m.hack", 0x1000);
241     vmstate_register_ram_global(hack);
242     memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
243
244     qemu_register_reset(armv7m_reset, env);
245     return pic;
246 }
247
248 static SysBusDeviceInfo bitband_info = {
249     .init = bitband_init,
250     .qdev.name  = "ARM,bitband-memory",
251     .qdev.size  = sizeof(BitBandState),
252     .qdev.props = (Property[]) {
253         DEFINE_PROP_UINT32("base", BitBandState, base, 0),
254         DEFINE_PROP_END_OF_LIST(),
255     }
256 };
257
258 static void armv7m_register_devices(void)
259 {
260     sysbus_register_withprop(&bitband_info);
261 }
262
263 device_init(armv7m_register_devices)