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 "hw/sysbus.h"
11#include "hw/arm/arm.h"
12#include "sysemu/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.  */
17static 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
27static uint32_t bitband_readb(void *opaque, hwaddr 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
34static void bitband_writeb(void *opaque, hwaddr 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
50static uint32_t bitband_readw(void *opaque, hwaddr 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
62static void bitband_writew(void *opaque, hwaddr 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
79static uint32_t bitband_readl(void *opaque, hwaddr 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
91static void bitband_writel(void *opaque, hwaddr 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
108static CPUReadMemoryFunc * const bitband_readfn[] = {
109   bitband_readb,
110   bitband_readw,
111   bitband_readl
112};
113
114static CPUWriteMemoryFunc * const bitband_writefn[] = {
115   bitband_writeb,
116   bitband_writew,
117   bitband_writel
118};
119
120typedef struct {
121    SysBusDevice busdev;
122    uint32_t base;
123} BitBandState;
124
125static void bitband_init(SysBusDevice *dev)
126{
127    BitBandState *s = FROM_SYSBUS(BitBandState, dev);
128    int iomemtype;
129
130    s->base = qdev_get_prop_int(&dev->qdev, "base", 0);
131    iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn,
132                                       &s->base);
133    sysbus_init_mmio(dev, 0x02000000, iomemtype);
134}
135
136static void armv7m_bitband_init(void)
137{
138    DeviceState *dev;
139
140    dev = qdev_create(NULL, "ARM,bitband-memory");
141    qdev_set_prop_int(dev, "base", 0x20000000);
142    qdev_init(dev);
143    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
144
145    dev = qdev_create(NULL, "ARM,bitband-memory");
146    qdev_set_prop_int(dev, "base", 0x40000000);
147    qdev_init(dev);
148    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
149}
150
151/* Board init.  */
152/* Init CPU and memory for a v7-M based board.
153   flash_size and sram_size are in kb.
154   Returns the NVIC array.  */
155
156qemu_irq *armv7m_init(int flash_size, int sram_size,
157                      const char *kernel_filename, const char *cpu_model)
158{
159    CPUOldState *env;
160    DeviceState *nvic;
161    /* FIXME: make this local state.  */
162    static qemu_irq pic[64];
163    qemu_irq *cpu_pic;
164    uint32_t pc;
165    int image_size;
166    uint64_t entry;
167    uint64_t lowaddr;
168    int i;
169
170    flash_size *= 1024;
171    sram_size *= 1024;
172
173    if (!cpu_model)
174	cpu_model = "cortex-m3";
175    env = cpu_init(cpu_model);
176    if (!env) {
177        fprintf(stderr, "Unable to find CPU definition\n");
178        exit(1);
179    }
180
181#if 0
182    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
183       We don't have proper commandline options, so allocate half of memory
184       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
185    if (ram_size > (512 + 32) * 1024 * 1024)
186        ram_size = (512 + 32) * 1024 * 1024;
187    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
188    if (sram_size > 32 * 1024 * 1024)
189        sram_size = 32 * 1024 * 1024;
190    code_size = ram_size - sram_size;
191#endif
192
193    /* Flash programming is done via the SCU, so pretend it is ROM.  */
194    cpu_register_physical_memory(0, flash_size,
195                                 qemu_ram_alloc(NULL, "armv7m.flash",
196                                                flash_size) | IO_MEM_ROM);
197    cpu_register_physical_memory(0x20000000, sram_size,
198                                 qemu_ram_alloc(NULL, "armv7m.sram",
199                                                sram_size) | IO_MEM_RAM);
200    armv7m_bitband_init();
201
202    nvic = qdev_create(NULL, "armv7m_nvic");
203    env->nvic = nvic;
204    qdev_init(nvic);
205    cpu_pic = arm_pic_init_cpu(env);
206    sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
207    for (i = 0; i < 64; i++) {
208        pic[i] = qdev_get_gpio_in(nvic, i);
209    }
210
211    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
212    if (image_size < 0) {
213        image_size = load_image_targphys(kernel_filename, 0, flash_size);
214	lowaddr = 0;
215    }
216    if (image_size < 0) {
217        fprintf(stderr, "qemu: could not load kernel '%s'\n",
218                kernel_filename);
219        exit(1);
220    }
221
222    /* If the image was loaded at address zero then assume it is a
223       regular ROM image and perform the normal CPU reset sequence.
224       Otherwise jump directly to the entry point.  */
225    if (lowaddr == 0) {
226	env->regs[13] = ldl_phys(0);
227	pc = ldl_phys(4);
228    } else {
229	pc = entry;
230    }
231    env->thumb = pc & 1;
232    env->regs[15] = pc & ~1;
233
234    /* Hack to map an additional page of ram at the top of the address
235       space.  This stops qemu complaining about executing code outside RAM
236       when returning from an exception.  */
237    cpu_register_physical_memory(0xfffff000, 0x1000,
238                                 qemu_ram_alloc(NULL, "armv7m.hack",
239                                                0x1000) | IO_MEM_RAM);
240    return pic;
241}
242
243static void armv7m_register_devices(void)
244{
245    sysbus_register_dev("ARM,bitband-memory", sizeof(BitBandState),
246                        bitband_init);
247}
248
249device_init(armv7m_register_devices)
250