Statistics
| Branch: | Revision:

root / hw / armv7m.c @ a8b7063b

History | View | Annotate | Download (6.7 kB)

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