Statistics
| Branch: | Revision:

root / hw / armv7m.c @ a08784dd

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 "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 acess.  */
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 CPUReadMemoryFunc * const bitband_readfn[] = {
110
   bitband_readb,
111
   bitband_readw,
112
   bitband_readl
113
};
114

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

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

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

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

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

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

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

    
152
/* Board init.  */
153

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

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

    
163
qemu_irq *armv7m_init(int flash_size, int sram_size,
164
                      const char *kernel_filename, const char *cpu_model)
165
{
166
    CPUState *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

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

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

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

    
200
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
201
    cpu_register_physical_memory(0, flash_size,
202
                                 qemu_ram_alloc(NULL, "armv7m.flash",
203
                                                flash_size) | IO_MEM_ROM);
204
    cpu_register_physical_memory(0x20000000, sram_size,
205
                                 qemu_ram_alloc(NULL, "armv7m.sram",
206
                                                sram_size) | IO_MEM_RAM);
207
    armv7m_bitband_init();
208

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

    
218
#ifdef TARGET_WORDS_BIGENDIAN
219
    big_endian = 1;
220
#else
221
    big_endian = 0;
222
#endif
223

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

    
236
    /* Hack to map an additional page of ram at the top of the address
237
       space.  This stops qemu complaining about executing code outside RAM
238
       when returning from an exception.  */
239
    cpu_register_physical_memory(0xfffff000, 0x1000,
240
                                 qemu_ram_alloc(NULL, "armv7m.hack", 
241
                                                0x1000) | IO_MEM_RAM);
242

    
243
    qemu_register_reset(armv7m_reset, env);
244
    return pic;
245
}
246

    
247
static SysBusDeviceInfo bitband_info = {
248
    .init = bitband_init,
249
    .qdev.name  = "ARM,bitband-memory",
250
    .qdev.size  = sizeof(BitBandState),
251
    .qdev.props = (Property[]) {
252
        DEFINE_PROP_UINT32("base", BitBandState, base, 0),
253
        DEFINE_PROP_END_OF_LIST(),
254
    }
255
};
256

    
257
static void armv7m_register_devices(void)
258
{
259
    sysbus_register_withprop(&bitband_info);
260
}
261

    
262
device_init(armv7m_register_devices)