Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 0f37c99b

History | View | Annotate | Download (7.5 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 "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_state_reset((CPUARMState *)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
    ARMCPU *cpu;
164
    CPUARMState *env;
165
    DeviceState *nvic;
166
    /* FIXME: make this local state.  */
167
    static qemu_irq pic[64];
168
    qemu_irq *cpu_pic;
169
    int image_size;
170
    uint64_t entry;
171
    uint64_t lowaddr;
172
    int i;
173
    int big_endian;
174
    MemoryRegion *sram = g_new(MemoryRegion, 1);
175
    MemoryRegion *flash = g_new(MemoryRegion, 1);
176
    MemoryRegion *hack = g_new(MemoryRegion, 1);
177

    
178
    flash_size *= 1024;
179
    sram_size *= 1024;
180

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

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

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

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

    
222
#ifdef TARGET_WORDS_BIGENDIAN
223
    big_endian = 1;
224
#else
225
    big_endian = 0;
226
#endif
227

    
228
    image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
229
                          NULL, big_endian, ELF_MACHINE, 1);
230
    if (image_size < 0) {
231
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
232
        lowaddr = 0;
233
    }
234
    if (image_size < 0) {
235
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
236
                kernel_filename);
237
        exit(1);
238
    }
239

    
240
    /* Hack to map an additional page of ram at the top of the address
241
       space.  This stops qemu complaining about executing code outside RAM
242
       when returning from an exception.  */
243
    memory_region_init_ram(hack, "armv7m.hack", 0x1000);
244
    vmstate_register_ram_global(hack);
245
    memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
246

    
247
    qemu_register_reset(armv7m_reset, env);
248
    return pic;
249
}
250

    
251
static Property bitband_properties[] = {
252
    DEFINE_PROP_UINT32("base", BitBandState, base, 0),
253
    DEFINE_PROP_END_OF_LIST(),
254
};
255

    
256
static void bitband_class_init(ObjectClass *klass, void *data)
257
{
258
    DeviceClass *dc = DEVICE_CLASS(klass);
259
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
260

    
261
    k->init = bitband_init;
262
    dc->props = bitband_properties;
263
}
264

    
265
static TypeInfo bitband_info = {
266
    .name          = "ARM,bitband-memory",
267
    .parent        = TYPE_SYS_BUS_DEVICE,
268
    .instance_size = sizeof(BitBandState),
269
    .class_init    = bitband_class_init,
270
};
271

    
272
static void armv7m_register_types(void)
273
{
274
    type_register_static(&bitband_info);
275
}
276

    
277
type_init(armv7m_register_types)