Statistics
| Branch: | Revision:

root / hw / armv7m.c @ d7585251

History | View | Annotate | Download (5.8 kB)

1 9ee6e8bb pbrook
/*
2 9ee6e8bb pbrook
 * ARMV7M System emulation.
3 9ee6e8bb pbrook
 *
4 9ee6e8bb pbrook
 * Copyright (c) 2006-2007 CodeSourcery.
5 9ee6e8bb pbrook
 * Written by Paul Brook
6 9ee6e8bb pbrook
 *
7 9ee6e8bb pbrook
 * This code is licenced under the GPL.
8 9ee6e8bb pbrook
 */
9 9ee6e8bb pbrook
10 87ecb68b pbrook
#include "hw.h"
11 87ecb68b pbrook
#include "arm-misc.h"
12 87ecb68b pbrook
#include "sysemu.h"
13 9ee6e8bb pbrook
14 9ee6e8bb pbrook
/* Bitbanded IO.  Each word corresponds to a single bit.  */
15 9ee6e8bb pbrook
16 9ee6e8bb pbrook
/* Get the byte address of the real memory for a bitband acess.  */
17 8da3ff18 pbrook
static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
18 9ee6e8bb pbrook
{
19 9ee6e8bb pbrook
    uint32_t res;
20 9ee6e8bb pbrook
21 8da3ff18 pbrook
    res = *(uint32_t *)opaque;
22 9ee6e8bb pbrook
    res |= (addr & 0x1ffffff) >> 5;
23 9ee6e8bb pbrook
    return res;
24 9ee6e8bb pbrook
25 9ee6e8bb pbrook
}
26 9ee6e8bb pbrook
27 9ee6e8bb pbrook
static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset)
28 9ee6e8bb pbrook
{
29 9ee6e8bb pbrook
    uint8_t v;
30 8da3ff18 pbrook
    cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
31 9ee6e8bb pbrook
    return (v & (1 << ((offset >> 2) & 7))) != 0;
32 9ee6e8bb pbrook
}
33 9ee6e8bb pbrook
34 9ee6e8bb pbrook
static void bitband_writeb(void *opaque, target_phys_addr_t offset,
35 9ee6e8bb pbrook
                           uint32_t value)
36 9ee6e8bb pbrook
{
37 9ee6e8bb pbrook
    uint32_t addr;
38 9ee6e8bb pbrook
    uint8_t mask;
39 9ee6e8bb pbrook
    uint8_t v;
40 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset);
41 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 7));
42 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, &v, 1);
43 9ee6e8bb pbrook
    if (value & 1)
44 9ee6e8bb pbrook
        v |= mask;
45 9ee6e8bb pbrook
    else
46 9ee6e8bb pbrook
        v &= ~mask;
47 9ee6e8bb pbrook
    cpu_physical_memory_write(addr, &v, 1);
48 9ee6e8bb pbrook
}
49 9ee6e8bb pbrook
50 9ee6e8bb pbrook
static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset)
51 9ee6e8bb pbrook
{
52 9ee6e8bb pbrook
    uint32_t addr;
53 9ee6e8bb pbrook
    uint16_t mask;
54 9ee6e8bb pbrook
    uint16_t v;
55 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~1;
56 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 15));
57 9ee6e8bb pbrook
    mask = tswap16(mask);
58 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
59 9ee6e8bb pbrook
    return (v & mask) != 0;
60 9ee6e8bb pbrook
}
61 9ee6e8bb pbrook
62 9ee6e8bb pbrook
static void bitband_writew(void *opaque, target_phys_addr_t offset,
63 9ee6e8bb pbrook
                           uint32_t value)
64 9ee6e8bb pbrook
{
65 9ee6e8bb pbrook
    uint32_t addr;
66 9ee6e8bb pbrook
    uint16_t mask;
67 9ee6e8bb pbrook
    uint16_t v;
68 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~1;
69 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 15));
70 9ee6e8bb pbrook
    mask = tswap16(mask);
71 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
72 9ee6e8bb pbrook
    if (value & 1)
73 9ee6e8bb pbrook
        v |= mask;
74 9ee6e8bb pbrook
    else
75 9ee6e8bb pbrook
        v &= ~mask;
76 9ee6e8bb pbrook
    cpu_physical_memory_write(addr, (uint8_t *)&v, 2);
77 9ee6e8bb pbrook
}
78 9ee6e8bb pbrook
79 9ee6e8bb pbrook
static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset)
80 9ee6e8bb pbrook
{
81 9ee6e8bb pbrook
    uint32_t addr;
82 9ee6e8bb pbrook
    uint32_t mask;
83 9ee6e8bb pbrook
    uint32_t v;
84 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~3;
85 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 31));
86 9ee6e8bb pbrook
    mask = tswap32(mask);
87 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
88 9ee6e8bb pbrook
    return (v & mask) != 0;
89 9ee6e8bb pbrook
}
90 9ee6e8bb pbrook
91 9ee6e8bb pbrook
static void bitband_writel(void *opaque, target_phys_addr_t offset,
92 9ee6e8bb pbrook
                           uint32_t value)
93 9ee6e8bb pbrook
{
94 9ee6e8bb pbrook
    uint32_t addr;
95 9ee6e8bb pbrook
    uint32_t mask;
96 9ee6e8bb pbrook
    uint32_t v;
97 8da3ff18 pbrook
    addr = bitband_addr(opaque, offset) & ~3;
98 9ee6e8bb pbrook
    mask = (1 << ((offset >> 2) & 31));
99 9ee6e8bb pbrook
    mask = tswap32(mask);
100 9ee6e8bb pbrook
    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
101 9ee6e8bb pbrook
    if (value & 1)
102 9ee6e8bb pbrook
        v |= mask;
103 9ee6e8bb pbrook
    else
104 9ee6e8bb pbrook
        v &= ~mask;
105 9ee6e8bb pbrook
    cpu_physical_memory_write(addr, (uint8_t *)&v, 4);
106 9ee6e8bb pbrook
}
107 9ee6e8bb pbrook
108 9ee6e8bb pbrook
static CPUReadMemoryFunc *bitband_readfn[] = {
109 9ee6e8bb pbrook
   bitband_readb,
110 9ee6e8bb pbrook
   bitband_readw,
111 9ee6e8bb pbrook
   bitband_readl
112 9ee6e8bb pbrook
};
113 9ee6e8bb pbrook
114 9ee6e8bb pbrook
static CPUWriteMemoryFunc *bitband_writefn[] = {
115 9ee6e8bb pbrook
   bitband_writeb,
116 9ee6e8bb pbrook
   bitband_writew,
117 9ee6e8bb pbrook
   bitband_writel
118 9ee6e8bb pbrook
};
119 9ee6e8bb pbrook
120 9ee6e8bb pbrook
static void armv7m_bitband_init(void)
121 9ee6e8bb pbrook
{
122 9ee6e8bb pbrook
    int iomemtype;
123 8da3ff18 pbrook
    static uint32_t bitband1_offset = 0x20000000;
124 8da3ff18 pbrook
    static uint32_t bitband2_offset = 0x40000000;
125 9ee6e8bb pbrook
126 9ee6e8bb pbrook
    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
127 8da3ff18 pbrook
                                       &bitband1_offset);
128 9ee6e8bb pbrook
    cpu_register_physical_memory(0x22000000, 0x02000000, iomemtype);
129 8da3ff18 pbrook
    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
130 8da3ff18 pbrook
                                       &bitband2_offset);
131 9ee6e8bb pbrook
    cpu_register_physical_memory(0x42000000, 0x02000000, iomemtype);
132 9ee6e8bb pbrook
}
133 9ee6e8bb pbrook
134 9ee6e8bb pbrook
/* Board init.  */
135 9ee6e8bb pbrook
/* Init CPU and memory for a v7-M based board.
136 9ee6e8bb pbrook
   flash_size and sram_size are in kb.
137 9ee6e8bb pbrook
   Returns the NVIC array.  */
138 9ee6e8bb pbrook
139 9ee6e8bb pbrook
qemu_irq *armv7m_init(int flash_size, int sram_size,
140 9ee6e8bb pbrook
                      const char *kernel_filename, const char *cpu_model)
141 9ee6e8bb pbrook
{
142 9ee6e8bb pbrook
    CPUState *env;
143 9ee6e8bb pbrook
    qemu_irq *pic;
144 9ee6e8bb pbrook
    uint32_t pc;
145 9ee6e8bb pbrook
    int image_size;
146 9ee6e8bb pbrook
    uint64_t entry;
147 9ee6e8bb pbrook
    uint64_t lowaddr;
148 9ee6e8bb pbrook
149 9ee6e8bb pbrook
    flash_size *= 1024;
150 9ee6e8bb pbrook
    sram_size *= 1024;
151 9ee6e8bb pbrook
152 9ee6e8bb pbrook
    if (!cpu_model)
153 9ee6e8bb pbrook
        cpu_model = "cortex-m3";
154 9ee6e8bb pbrook
    env = cpu_init(cpu_model);
155 9ee6e8bb pbrook
    if (!env) {
156 9ee6e8bb pbrook
        fprintf(stderr, "Unable to find CPU definition\n");
157 9ee6e8bb pbrook
        exit(1);
158 9ee6e8bb pbrook
    }
159 9ee6e8bb pbrook
160 9ee6e8bb pbrook
#if 0
161 9ee6e8bb pbrook
    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
162 9ee6e8bb pbrook
       We don't have proper commandline options, so allocate half of memory
163 9ee6e8bb pbrook
       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
164 9ee6e8bb pbrook
    if (ram_size > (512 + 32) * 1024 * 1024)
165 9ee6e8bb pbrook
        ram_size = (512 + 32) * 1024 * 1024;
166 9ee6e8bb pbrook
    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
167 9ee6e8bb pbrook
    if (sram_size > 32 * 1024 * 1024)
168 9ee6e8bb pbrook
        sram_size = 32 * 1024 * 1024;
169 9ee6e8bb pbrook
    code_size = ram_size - sram_size;
170 9ee6e8bb pbrook
#endif
171 9ee6e8bb pbrook
172 9ee6e8bb pbrook
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
173 dcac9679 pbrook
    cpu_register_physical_memory(0, flash_size,
174 dcac9679 pbrook
                                 qemu_ram_alloc(flash_size) | IO_MEM_ROM);
175 9ee6e8bb pbrook
    cpu_register_physical_memory(0x20000000, sram_size,
176 dcac9679 pbrook
                                 qemu_ram_alloc(sram_size) | IO_MEM_RAM);
177 9ee6e8bb pbrook
    armv7m_bitband_init();
178 9ee6e8bb pbrook
179 9ee6e8bb pbrook
    pic = armv7m_nvic_init(env);
180 9ee6e8bb pbrook
181 9ee6e8bb pbrook
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
182 9ee6e8bb pbrook
    if (image_size < 0) {
183 dcac9679 pbrook
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
184 9ee6e8bb pbrook
        lowaddr = 0;
185 9ee6e8bb pbrook
    }
186 9ee6e8bb pbrook
    if (image_size < 0) {
187 9ee6e8bb pbrook
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
188 9ee6e8bb pbrook
                kernel_filename);
189 9ee6e8bb pbrook
        exit(1);
190 9ee6e8bb pbrook
    }
191 9ee6e8bb pbrook
192 9ee6e8bb pbrook
    /* If the image was loaded at address zero then assume it is a
193 9ee6e8bb pbrook
       regular ROM image and perform the normal CPU reset sequence.
194 9ee6e8bb pbrook
       Otherwise jump directly to the entry point.  */
195 9ee6e8bb pbrook
    if (lowaddr == 0) {
196 44654490 pbrook
        env->regs[13] = ldl_phys(0);
197 44654490 pbrook
        pc = ldl_phys(4);
198 9ee6e8bb pbrook
    } else {
199 9ee6e8bb pbrook
        pc = entry;
200 9ee6e8bb pbrook
    }
201 9ee6e8bb pbrook
    env->thumb = pc & 1;
202 9ee6e8bb pbrook
    env->regs[15] = pc & ~1;
203 9ee6e8bb pbrook
204 9ee6e8bb pbrook
    /* Hack to map an additional page of ram at the top of the address
205 9ee6e8bb pbrook
       space.  This stops qemu complaining about executing code outside RAM
206 9ee6e8bb pbrook
       when returning from an exception.  */
207 dcac9679 pbrook
    cpu_register_physical_memory(0xfffff000, 0x1000,
208 dcac9679 pbrook
                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
209 9ee6e8bb pbrook
210 9ee6e8bb pbrook
    return pic;
211 9ee6e8bb pbrook
}