Statistics
| Branch: | Revision:

root / hw / armv7m.c @ fe7e8758

History | View | Annotate | Download (6.2 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 *bitband_readfn[] = {
109
   bitband_readb,
110
   bitband_readw,
111
   bitband_readl
112
};
113

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

    
120
static void armv7m_bitband_init(void)
121
{
122
    int iomemtype;
123
    static uint32_t bitband1_offset = 0x20000000;
124
    static uint32_t bitband2_offset = 0x40000000;
125

    
126
    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
127
                                       &bitband1_offset);
128
    cpu_register_physical_memory(0x22000000, 0x02000000, iomemtype);
129
    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
130
                                       &bitband2_offset);
131
    cpu_register_physical_memory(0x42000000, 0x02000000, iomemtype);
132
}
133

    
134
/* Board init.  */
135
/* Init CPU and memory for a v7-M based board.
136
   flash_size and sram_size are in kb.
137
   Returns the NVIC array.  */
138

    
139
qemu_irq *armv7m_init(int flash_size, int sram_size,
140
                      const char *kernel_filename, const char *cpu_model)
141
{
142
    CPUState *env;
143
    DeviceState *nvic;
144
    /* FIXME: make this local state.  */
145
    static qemu_irq pic[64];
146
    qemu_irq *cpu_pic;
147
    uint32_t pc;
148
    int image_size;
149
    uint64_t entry;
150
    uint64_t lowaddr;
151
    int i;
152

    
153
    flash_size *= 1024;
154
    sram_size *= 1024;
155

    
156
    if (!cpu_model)
157
        cpu_model = "cortex-m3";
158
    env = cpu_init(cpu_model);
159
    if (!env) {
160
        fprintf(stderr, "Unable to find CPU definition\n");
161
        exit(1);
162
    }
163

    
164
#if 0
165
    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
166
       We don't have proper commandline options, so allocate half of memory
167
       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
168
    if (ram_size > (512 + 32) * 1024 * 1024)
169
        ram_size = (512 + 32) * 1024 * 1024;
170
    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
171
    if (sram_size > 32 * 1024 * 1024)
172
        sram_size = 32 * 1024 * 1024;
173
    code_size = ram_size - sram_size;
174
#endif
175

    
176
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
177
    cpu_register_physical_memory(0, flash_size,
178
                                 qemu_ram_alloc(flash_size) | IO_MEM_ROM);
179
    cpu_register_physical_memory(0x20000000, sram_size,
180
                                 qemu_ram_alloc(sram_size) | IO_MEM_RAM);
181
    armv7m_bitband_init();
182

    
183
    nvic = qdev_create(NULL, "armv7m_nvic");
184
    qdev_set_prop_ptr(nvic, "cpu", env);
185
    qdev_init(nvic);
186
    cpu_pic = arm_pic_init_cpu(env);
187
    sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
188
    for (i = 0; i < 64; i++) {
189
        pic[i] = qdev_get_irq_sink(nvic, i);
190
    }
191

    
192
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
193
    if (image_size < 0) {
194
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
195
        lowaddr = 0;
196
    }
197
    if (image_size < 0) {
198
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
199
                kernel_filename);
200
        exit(1);
201
    }
202

    
203
    /* If the image was loaded at address zero then assume it is a
204
       regular ROM image and perform the normal CPU reset sequence.
205
       Otherwise jump directly to the entry point.  */
206
    if (lowaddr == 0) {
207
        env->regs[13] = ldl_phys(0);
208
        pc = ldl_phys(4);
209
    } else {
210
        pc = entry;
211
    }
212
    env->thumb = pc & 1;
213
    env->regs[15] = pc & ~1;
214

    
215
    /* Hack to map an additional page of ram at the top of the address
216
       space.  This stops qemu complaining about executing code outside RAM
217
       when returning from an exception.  */
218
    cpu_register_physical_memory(0xfffff000, 0x1000,
219
                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
220

    
221
    return pic;
222
}