Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 81a322d4

History | View | Annotate | Download (6.8 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

    
14
/* Bitbanded IO.  Each word corresponds to a single bit.  */
15

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

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

    
25
}
26

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
151
/* Board init.  */
152
/* Init CPU and memory for a v7-M based board.
153
   flash_size and sram_size are in kb.
154
   Returns the NVIC array.  */
155

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

    
170
    flash_size *= 1024;
171
    sram_size *= 1024;
172

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

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

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

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

    
209
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
210
    if (image_size < 0) {
211
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
212
        lowaddr = 0;
213
    }
214
    if (image_size < 0) {
215
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
216
                kernel_filename);
217
        exit(1);
218
    }
219

    
220
    /* If the image was loaded at address zero then assume it is a
221
       regular ROM image and perform the normal CPU reset sequence.
222
       Otherwise jump directly to the entry point.  */
223
    if (lowaddr == 0) {
224
        env->regs[13] = ldl_phys(0);
225
        pc = ldl_phys(4);
226
    } else {
227
        pc = entry;
228
    }
229
    env->thumb = pc & 1;
230
    env->regs[15] = pc & ~1;
231

    
232
    /* Hack to map an additional page of ram at the top of the address
233
       space.  This stops qemu complaining about executing code outside RAM
234
       when returning from an exception.  */
235
    cpu_register_physical_memory(0xfffff000, 0x1000,
236
                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
237

    
238
    return pic;
239
}
240

    
241
static SysBusDeviceInfo bitband_info = {
242
    .init = bitband_init,
243
    .qdev.name  = "ARM,bitband-memory",
244
    .qdev.size  = sizeof(BitBandState),
245
    .qdev.props = (Property[]) {
246
        DEFINE_PROP_UINT32("base", BitBandState, base, 0),
247
        DEFINE_PROP_END_OF_LIST(),
248
    }
249
};
250

    
251
static void armv7m_register_devices(void)
252
{
253
    sysbus_register_withprop(&bitband_info);
254
}
255

    
256
device_init(armv7m_register_devices)