Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 1a1ea6f0

History | View | Annotate | Download (7 kB)

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 "sysbus.h"
11
#include "arm-misc.h"
12
#include "sysemu.h"
13
#include "loader.h"
14
#include "elf.h"
15

    
16
/* Bitbanded IO.  Each word corresponds to a single bit.  */
17

    
18
/* Get the byte address of the real memory for a bitband acess.  */
19
static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
20
{
21
    uint32_t res;
22

    
23
    res = *(uint32_t *)opaque;
24
    res |= (addr & 0x1ffffff) >> 5;
25
    return res;
26

    
27
}
28

    
29
static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset)
30
{
31
    uint8_t v;
32
    cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
33
    return (v & (1 << ((offset >> 2) & 7))) != 0;
34
}
35

    
36
static void bitband_writeb(void *opaque, target_phys_addr_t offset,
37
                           uint32_t value)
38
{
39
    uint32_t addr;
40
    uint8_t mask;
41
    uint8_t v;
42
    addr = bitband_addr(opaque, offset);
43
    mask = (1 << ((offset >> 2) & 7));
44
    cpu_physical_memory_read(addr, &v, 1);
45
    if (value & 1)
46
        v |= mask;
47
    else
48
        v &= ~mask;
49
    cpu_physical_memory_write(addr, &v, 1);
50
}
51

    
52
static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset)
53
{
54
    uint32_t addr;
55
    uint16_t mask;
56
    uint16_t v;
57
    addr = bitband_addr(opaque, offset) & ~1;
58
    mask = (1 << ((offset >> 2) & 15));
59
    mask = tswap16(mask);
60
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
61
    return (v & mask) != 0;
62
}
63

    
64
static void bitband_writew(void *opaque, target_phys_addr_t offset,
65
                           uint32_t value)
66
{
67
    uint32_t addr;
68
    uint16_t mask;
69
    uint16_t v;
70
    addr = bitband_addr(opaque, offset) & ~1;
71
    mask = (1 << ((offset >> 2) & 15));
72
    mask = tswap16(mask);
73
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
74
    if (value & 1)
75
        v |= mask;
76
    else
77
        v &= ~mask;
78
    cpu_physical_memory_write(addr, (uint8_t *)&v, 2);
79
}
80

    
81
static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset)
82
{
83
    uint32_t addr;
84
    uint32_t mask;
85
    uint32_t v;
86
    addr = bitband_addr(opaque, offset) & ~3;
87
    mask = (1 << ((offset >> 2) & 31));
88
    mask = tswap32(mask);
89
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
90
    return (v & mask) != 0;
91
}
92

    
93
static void bitband_writel(void *opaque, target_phys_addr_t offset,
94
                           uint32_t value)
95
{
96
    uint32_t addr;
97
    uint32_t mask;
98
    uint32_t v;
99
    addr = bitband_addr(opaque, offset) & ~3;
100
    mask = (1 << ((offset >> 2) & 31));
101
    mask = tswap32(mask);
102
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
103
    if (value & 1)
104
        v |= mask;
105
    else
106
        v &= ~mask;
107
    cpu_physical_memory_write(addr, (uint8_t *)&v, 4);
108
}
109

    
110
static CPUReadMemoryFunc * const bitband_readfn[] = {
111
   bitband_readb,
112
   bitband_readw,
113
   bitband_readl
114
};
115

    
116
static CPUWriteMemoryFunc * const bitband_writefn[] = {
117
   bitband_writeb,
118
   bitband_writew,
119
   bitband_writel
120
};
121

    
122
typedef struct {
123
    SysBusDevice busdev;
124
    uint32_t base;
125
} BitBandState;
126

    
127
static int bitband_init(SysBusDevice *dev)
128
{
129
    BitBandState *s = FROM_SYSBUS(BitBandState, dev);
130
    int iomemtype;
131

    
132
    iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn,
133
                                       &s->base);
134
    sysbus_init_mmio(dev, 0x02000000, iomemtype);
135
    return 0;
136
}
137

    
138
static void armv7m_bitband_init(void)
139
{
140
    DeviceState *dev;
141

    
142
    dev = qdev_create(NULL, "ARM,bitband-memory");
143
    qdev_prop_set_uint32(dev, "base", 0x20000000);
144
    qdev_init_nofail(dev);
145
    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
146

    
147
    dev = qdev_create(NULL, "ARM,bitband-memory");
148
    qdev_prop_set_uint32(dev, "base", 0x40000000);
149
    qdev_init_nofail(dev);
150
    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
151
}
152

    
153
/* Board init.  */
154

    
155
static void armv7m_reset(void *opaque)
156
{
157
    cpu_reset((CPUState *)opaque);
158
}
159

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

    
164
qemu_irq *armv7m_init(int flash_size, int sram_size,
165
                      const char *kernel_filename, const char *cpu_model)
166
{
167
    CPUState *env;
168
    DeviceState *nvic;
169
    /* FIXME: make this local state.  */
170
    static qemu_irq pic[64];
171
    qemu_irq *cpu_pic;
172
    int image_size;
173
    uint64_t entry;
174
    uint64_t lowaddr;
175
    int i;
176
    int big_endian;
177

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

    
181
    if (!cpu_model)
182
        cpu_model = "cortex-m3";
183
    env = cpu_init(cpu_model);
184
    if (!env) {
185
        fprintf(stderr, "Unable to find CPU definition\n");
186
        exit(1);
187
    }
188

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

    
201
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
202
    cpu_register_physical_memory(0, flash_size,
203
                                 qemu_ram_alloc(NULL, "armv7m.flash",
204
                                                flash_size) | IO_MEM_ROM);
205
    cpu_register_physical_memory(0x20000000, sram_size,
206
                                 qemu_ram_alloc(NULL, "armv7m.sram",
207
                                                sram_size) | IO_MEM_RAM);
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
    cpu_register_physical_memory(0xfffff000, 0x1000,
241
                                 qemu_ram_alloc(NULL, "armv7m.hack", 
242
                                                0x1000) | IO_MEM_RAM);
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)