Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 731ba0ce

History | View | Annotate | Download (5.5 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 9ee6e8bb pbrook
static inline uint32_t bitband_addr(uint32_t addr)
18 9ee6e8bb pbrook
{
19 9ee6e8bb pbrook
    uint32_t res;
20 9ee6e8bb pbrook
21 9ee6e8bb pbrook
    res = addr & 0xe0000000;
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 9ee6e8bb pbrook
    cpu_physical_memory_read(bitband_addr(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 9ee6e8bb pbrook
    addr = bitband_addr(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 9ee6e8bb pbrook
    addr = bitband_addr(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 9ee6e8bb pbrook
    addr = bitband_addr(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 9ee6e8bb pbrook
    addr = bitband_addr(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 9ee6e8bb pbrook
    addr = bitband_addr(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 9ee6e8bb pbrook
124 9ee6e8bb pbrook
    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
125 9ee6e8bb pbrook
                                       NULL);
126 9ee6e8bb pbrook
    cpu_register_physical_memory(0x22000000, 0x02000000, iomemtype);
127 9ee6e8bb pbrook
    cpu_register_physical_memory(0x42000000, 0x02000000, iomemtype);
128 9ee6e8bb pbrook
}
129 9ee6e8bb pbrook
130 9ee6e8bb pbrook
/* Board init.  */
131 9ee6e8bb pbrook
/* Init CPU and memory for a v7-M based board.
132 9ee6e8bb pbrook
   flash_size and sram_size are in kb.
133 9ee6e8bb pbrook
   Returns the NVIC array.  */
134 9ee6e8bb pbrook
135 9ee6e8bb pbrook
qemu_irq *armv7m_init(int flash_size, int sram_size,
136 9ee6e8bb pbrook
                      const char *kernel_filename, const char *cpu_model)
137 9ee6e8bb pbrook
{
138 9ee6e8bb pbrook
    CPUState *env;
139 9ee6e8bb pbrook
    qemu_irq *pic;
140 9ee6e8bb pbrook
    uint32_t pc;
141 9ee6e8bb pbrook
    int image_size;
142 9ee6e8bb pbrook
    uint64_t entry;
143 9ee6e8bb pbrook
    uint64_t lowaddr;
144 9ee6e8bb pbrook
145 9ee6e8bb pbrook
    flash_size *= 1024;
146 9ee6e8bb pbrook
    sram_size *= 1024;
147 9ee6e8bb pbrook
148 9ee6e8bb pbrook
    if (!cpu_model)
149 9ee6e8bb pbrook
        cpu_model = "cortex-m3";
150 9ee6e8bb pbrook
    env = cpu_init(cpu_model);
151 9ee6e8bb pbrook
    if (!env) {
152 9ee6e8bb pbrook
        fprintf(stderr, "Unable to find CPU definition\n");
153 9ee6e8bb pbrook
        exit(1);
154 9ee6e8bb pbrook
    }
155 9ee6e8bb pbrook
156 9ee6e8bb pbrook
#if 0
157 9ee6e8bb pbrook
    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
158 9ee6e8bb pbrook
       We don't have proper commandline options, so allocate half of memory
159 9ee6e8bb pbrook
       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
160 9ee6e8bb pbrook
    if (ram_size > (512 + 32) * 1024 * 1024)
161 9ee6e8bb pbrook
        ram_size = (512 + 32) * 1024 * 1024;
162 9ee6e8bb pbrook
    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
163 9ee6e8bb pbrook
    if (sram_size > 32 * 1024 * 1024)
164 9ee6e8bb pbrook
        sram_size = 32 * 1024 * 1024;
165 9ee6e8bb pbrook
    code_size = ram_size - sram_size;
166 9ee6e8bb pbrook
#endif
167 9ee6e8bb pbrook
168 9ee6e8bb pbrook
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
169 9ee6e8bb pbrook
    cpu_register_physical_memory(0, flash_size, IO_MEM_ROM);
170 9ee6e8bb pbrook
    cpu_register_physical_memory(0x20000000, sram_size,
171 9ee6e8bb pbrook
                                 flash_size + IO_MEM_RAM);
172 9ee6e8bb pbrook
    armv7m_bitband_init();
173 9ee6e8bb pbrook
174 9ee6e8bb pbrook
    pic = armv7m_nvic_init(env);
175 9ee6e8bb pbrook
176 9ee6e8bb pbrook
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
177 9ee6e8bb pbrook
    if (image_size < 0) {
178 9ee6e8bb pbrook
        image_size = load_image(kernel_filename, phys_ram_base);
179 9ee6e8bb pbrook
        lowaddr = 0;
180 9ee6e8bb pbrook
    }
181 9ee6e8bb pbrook
    if (image_size < 0) {
182 9ee6e8bb pbrook
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
183 9ee6e8bb pbrook
                kernel_filename);
184 9ee6e8bb pbrook
        exit(1);
185 9ee6e8bb pbrook
    }
186 9ee6e8bb pbrook
187 9ee6e8bb pbrook
    /* If the image was loaded at address zero then assume it is a
188 9ee6e8bb pbrook
       regular ROM image and perform the normal CPU reset sequence.
189 9ee6e8bb pbrook
       Otherwise jump directly to the entry point.  */
190 9ee6e8bb pbrook
    if (lowaddr == 0) {
191 9ee6e8bb pbrook
        env->regs[13] = tswap32(*(uint32_t *)phys_ram_base);
192 9ee6e8bb pbrook
        pc = tswap32(*(uint32_t *)(phys_ram_base + 4));
193 9ee6e8bb pbrook
    } else {
194 9ee6e8bb pbrook
        pc = entry;
195 9ee6e8bb pbrook
    }
196 9ee6e8bb pbrook
    env->thumb = pc & 1;
197 9ee6e8bb pbrook
    env->regs[15] = pc & ~1;
198 9ee6e8bb pbrook
199 9ee6e8bb pbrook
    /* Hack to map an additional page of ram at the top of the address
200 9ee6e8bb pbrook
       space.  This stops qemu complaining about executing code outside RAM
201 9ee6e8bb pbrook
       when returning from an exception.  */
202 9ee6e8bb pbrook
    cpu_register_physical_memory(0xfffff000, 0x1000, IO_MEM_RAM + ram_size);
203 9ee6e8bb pbrook
204 9ee6e8bb pbrook
    return pic;
205 9ee6e8bb pbrook
}