Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 1d6198c3

History | View | Annotate | Download (5.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 "hw.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
    qemu_irq *pic;
144
    uint32_t pc;
145
    int image_size;
146
    uint64_t entry;
147
    uint64_t lowaddr;
148

    
149
    flash_size *= 1024;
150
    sram_size *= 1024;
151

    
152
    if (!cpu_model)
153
        cpu_model = "cortex-m3";
154
    env = cpu_init(cpu_model);
155
    if (!env) {
156
        fprintf(stderr, "Unable to find CPU definition\n");
157
        exit(1);
158
    }
159

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

    
172
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
173
    cpu_register_physical_memory(0, flash_size, IO_MEM_ROM);
174
    cpu_register_physical_memory(0x20000000, sram_size,
175
                                 flash_size + IO_MEM_RAM);
176
    armv7m_bitband_init();
177

    
178
    pic = armv7m_nvic_init(env);
179

    
180
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
181
    if (image_size < 0) {
182
        image_size = load_image(kernel_filename, phys_ram_base);
183
        lowaddr = 0;
184
    }
185
    if (image_size < 0) {
186
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
187
                kernel_filename);
188
        exit(1);
189
    }
190

    
191
    /* If the image was loaded at address zero then assume it is a
192
       regular ROM image and perform the normal CPU reset sequence.
193
       Otherwise jump directly to the entry point.  */
194
    if (lowaddr == 0) {
195
        env->regs[13] = tswap32(*(uint32_t *)phys_ram_base);
196
        pc = tswap32(*(uint32_t *)(phys_ram_base + 4));
197
    } else {
198
        pc = entry;
199
    }
200
    env->thumb = pc & 1;
201
    env->regs[15] = pc & ~1;
202

    
203
    /* Hack to map an additional page of ram at the top of the address
204
       space.  This stops qemu complaining about executing code outside RAM
205
       when returning from an exception.  */
206
    cpu_register_physical_memory(0xfffff000, 0x1000, IO_MEM_RAM + ram_size);
207

    
208
    return pic;
209
}