Statistics
| Branch: | Revision:

root / hw / arm / armv7m.c @ 0d09e41a

History | View | Annotate | Download (7.6 kB)

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 "hw/sysbus.h"
11
#include "hw/arm.h"
12
#include "hw/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, hwaddr 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, hwaddr 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, hwaddr 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, hwaddr 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, hwaddr 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, hwaddr 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(SYS_BUS_DEVICE(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(SYS_BUS_DEVICE(dev), 0, 0x42000000);
146
}
147

    
148
/* Board init.  */
149

    
150
static void armv7m_reset(void *opaque)
151
{
152
    ARMCPU *cpu = opaque;
153

    
154
    cpu_reset(CPU(cpu));
155
}
156

    
157
/* Init CPU and memory for a v7-M based board.
158
   flash_size and sram_size are in kb.
159
   Returns the NVIC array.  */
160

    
161
qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
162
                      int flash_size, int sram_size,
163
                      const char *kernel_filename, const char *cpu_model)
164
{
165
    ARMCPU *cpu;
166
    CPUARMState *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
    MemoryRegion *sram = g_new(MemoryRegion, 1);
177
    MemoryRegion *flash = g_new(MemoryRegion, 1);
178
    MemoryRegion *hack = g_new(MemoryRegion, 1);
179

    
180
    flash_size *= 1024;
181
    sram_size *= 1024;
182

    
183
    if (cpu_model == NULL) {
184
        cpu_model = "cortex-m3";
185
    }
186
    cpu = cpu_arm_init(cpu_model);
187
    if (cpu == NULL) {
188
        fprintf(stderr, "Unable to find CPU definition\n");
189
        exit(1);
190
    }
191
    env = &cpu->env;
192

    
193
#if 0
194
    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
195
       We don't have proper commandline options, so allocate half of memory
196
       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
197
    if (ram_size > (512 + 32) * 1024 * 1024)
198
        ram_size = (512 + 32) * 1024 * 1024;
199
    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
200
    if (sram_size > 32 * 1024 * 1024)
201
        sram_size = 32 * 1024 * 1024;
202
    code_size = ram_size - sram_size;
203
#endif
204

    
205
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
206
    memory_region_init_ram(flash, "armv7m.flash", flash_size);
207
    vmstate_register_ram_global(flash);
208
    memory_region_set_readonly(flash, true);
209
    memory_region_add_subregion(address_space_mem, 0, flash);
210
    memory_region_init_ram(sram, "armv7m.sram", sram_size);
211
    vmstate_register_ram_global(sram);
212
    memory_region_add_subregion(address_space_mem, 0x20000000, sram);
213
    armv7m_bitband_init();
214

    
215
    nvic = qdev_create(NULL, "armv7m_nvic");
216
    env->nvic = nvic;
217
    qdev_init_nofail(nvic);
218
    cpu_pic = arm_pic_init_cpu(cpu);
219
    sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
220
    for (i = 0; i < 64; i++) {
221
        pic[i] = qdev_get_gpio_in(nvic, i);
222
    }
223

    
224
#ifdef TARGET_WORDS_BIGENDIAN
225
    big_endian = 1;
226
#else
227
    big_endian = 0;
228
#endif
229

    
230
    if (!kernel_filename) {
231
        fprintf(stderr, "Guest image must be specified (using -kernel)\n");
232
        exit(1);
233
    }
234

    
235
    image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
236
                          NULL, big_endian, ELF_MACHINE, 1);
237
    if (image_size < 0) {
238
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
239
        lowaddr = 0;
240
    }
241
    if (image_size < 0) {
242
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
243
                kernel_filename);
244
        exit(1);
245
    }
246

    
247
    /* Hack to map an additional page of ram at the top of the address
248
       space.  This stops qemu complaining about executing code outside RAM
249
       when returning from an exception.  */
250
    memory_region_init_ram(hack, "armv7m.hack", 0x1000);
251
    vmstate_register_ram_global(hack);
252
    memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
253

    
254
    qemu_register_reset(armv7m_reset, cpu);
255
    return pic;
256
}
257

    
258
static Property bitband_properties[] = {
259
    DEFINE_PROP_UINT32("base", BitBandState, base, 0),
260
    DEFINE_PROP_END_OF_LIST(),
261
};
262

    
263
static void bitband_class_init(ObjectClass *klass, void *data)
264
{
265
    DeviceClass *dc = DEVICE_CLASS(klass);
266
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
267

    
268
    k->init = bitband_init;
269
    dc->props = bitband_properties;
270
}
271

    
272
static const TypeInfo bitband_info = {
273
    .name          = "ARM,bitband-memory",
274
    .parent        = TYPE_SYS_BUS_DEVICE,
275
    .instance_size = sizeof(BitBandState),
276
    .class_init    = bitband_class_init,
277
};
278

    
279
static void armv7m_register_types(void)
280
{
281
    type_register_static(&bitband_info);
282
}
283

    
284
type_init(armv7m_register_types)