Statistics
| Branch: | Revision:

root / hw / armv7m.c @ e23a1b33

History | View | Annotate | Download (7.1 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
/* Init CPU and memory for a v7-M based board.
155
   flash_size and sram_size are in kb.
156
   Returns the NVIC array.  */
157

    
158
qemu_irq *armv7m_init(int flash_size, int sram_size,
159
                      const char *kernel_filename, const char *cpu_model)
160
{
161
    CPUState *env;
162
    DeviceState *nvic;
163
    /* FIXME: make this local state.  */
164
    static qemu_irq pic[64];
165
    qemu_irq *cpu_pic;
166
    uint32_t pc;
167
    int image_size;
168
    uint64_t entry;
169
    uint64_t lowaddr;
170
    int i;
171
    int big_endian;
172

    
173
    flash_size *= 1024;
174
    sram_size *= 1024;
175

    
176
    if (!cpu_model)
177
        cpu_model = "cortex-m3";
178
    env = cpu_init(cpu_model);
179
    if (!env) {
180
        fprintf(stderr, "Unable to find CPU definition\n");
181
        exit(1);
182
    }
183

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

    
196
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
197
    cpu_register_physical_memory(0, flash_size,
198
                                 qemu_ram_alloc(flash_size) | IO_MEM_ROM);
199
    cpu_register_physical_memory(0x20000000, sram_size,
200
                                 qemu_ram_alloc(sram_size) | IO_MEM_RAM);
201
    armv7m_bitband_init();
202

    
203
    nvic = qdev_create(NULL, "armv7m_nvic");
204
    env->v7m.nvic = nvic;
205
    qdev_init_nofail(nvic);
206
    cpu_pic = arm_pic_init_cpu(env);
207
    sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
208
    for (i = 0; i < 64; i++) {
209
        pic[i] = qdev_get_gpio_in(nvic, i);
210
    }
211

    
212
#ifdef TARGET_WORDS_BIGENDIAN
213
    big_endian = 1;
214
#else
215
    big_endian = 0;
216
#endif
217

    
218
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL,
219
                          big_endian, ELF_MACHINE, 1);
220
    if (image_size < 0) {
221
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
222
        lowaddr = 0;
223
    }
224
    if (image_size < 0) {
225
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
226
                kernel_filename);
227
        exit(1);
228
    }
229

    
230
    /* If the image was loaded at address zero then assume it is a
231
       regular ROM image and perform the normal CPU reset sequence.
232
       Otherwise jump directly to the entry point.  */
233
    if (lowaddr == 0) {
234
        env->regs[13] = ldl_phys(0);
235
        pc = ldl_phys(4);
236
    } else {
237
        pc = entry;
238
    }
239
    env->thumb = pc & 1;
240
    env->regs[15] = pc & ~1;
241

    
242
    /* Hack to map an additional page of ram at the top of the address
243
       space.  This stops qemu complaining about executing code outside RAM
244
       when returning from an exception.  */
245
    cpu_register_physical_memory(0xfffff000, 0x1000,
246
                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
247

    
248
    return pic;
249
}
250

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

    
261
static void armv7m_register_devices(void)
262
{
263
    sysbus_register_withprop(&bitband_info);
264
}
265

    
266
device_init(armv7m_register_devices)