Statistics
| Branch: | Revision:

root / hw / armv7m.c @ 4af39611

History | View | Annotate | Download (6.2 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 fe7e8758 Paul Brook
#include "sysbus.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 fe7e8758 Paul Brook
    DeviceState *nvic;
144 fe7e8758 Paul Brook
    /* FIXME: make this local state.  */
145 fe7e8758 Paul Brook
    static qemu_irq pic[64];
146 fe7e8758 Paul Brook
    qemu_irq *cpu_pic;
147 9ee6e8bb pbrook
    uint32_t pc;
148 9ee6e8bb pbrook
    int image_size;
149 9ee6e8bb pbrook
    uint64_t entry;
150 9ee6e8bb pbrook
    uint64_t lowaddr;
151 fe7e8758 Paul Brook
    int i;
152 9ee6e8bb pbrook
153 9ee6e8bb pbrook
    flash_size *= 1024;
154 9ee6e8bb pbrook
    sram_size *= 1024;
155 9ee6e8bb pbrook
156 9ee6e8bb pbrook
    if (!cpu_model)
157 9ee6e8bb pbrook
        cpu_model = "cortex-m3";
158 9ee6e8bb pbrook
    env = cpu_init(cpu_model);
159 9ee6e8bb pbrook
    if (!env) {
160 9ee6e8bb pbrook
        fprintf(stderr, "Unable to find CPU definition\n");
161 9ee6e8bb pbrook
        exit(1);
162 9ee6e8bb pbrook
    }
163 9ee6e8bb pbrook
164 9ee6e8bb pbrook
#if 0
165 9ee6e8bb pbrook
    /* > 32Mb SRAM gets complicated because it overlaps the bitband area.
166 9ee6e8bb pbrook
       We don't have proper commandline options, so allocate half of memory
167 9ee6e8bb pbrook
       as SRAM, up to a maximum of 32Mb, and the rest as code.  */
168 9ee6e8bb pbrook
    if (ram_size > (512 + 32) * 1024 * 1024)
169 9ee6e8bb pbrook
        ram_size = (512 + 32) * 1024 * 1024;
170 9ee6e8bb pbrook
    sram_size = (ram_size / 2) & TARGET_PAGE_MASK;
171 9ee6e8bb pbrook
    if (sram_size > 32 * 1024 * 1024)
172 9ee6e8bb pbrook
        sram_size = 32 * 1024 * 1024;
173 9ee6e8bb pbrook
    code_size = ram_size - sram_size;
174 9ee6e8bb pbrook
#endif
175 9ee6e8bb pbrook
176 9ee6e8bb pbrook
    /* Flash programming is done via the SCU, so pretend it is ROM.  */
177 dcac9679 pbrook
    cpu_register_physical_memory(0, flash_size,
178 dcac9679 pbrook
                                 qemu_ram_alloc(flash_size) | IO_MEM_ROM);
179 9ee6e8bb pbrook
    cpu_register_physical_memory(0x20000000, sram_size,
180 dcac9679 pbrook
                                 qemu_ram_alloc(sram_size) | IO_MEM_RAM);
181 9ee6e8bb pbrook
    armv7m_bitband_init();
182 9ee6e8bb pbrook
183 fe7e8758 Paul Brook
    nvic = qdev_create(NULL, "armv7m_nvic");
184 fe7e8758 Paul Brook
    qdev_set_prop_ptr(nvic, "cpu", env);
185 fe7e8758 Paul Brook
    qdev_init(nvic);
186 fe7e8758 Paul Brook
    cpu_pic = arm_pic_init_cpu(env);
187 fe7e8758 Paul Brook
    sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
188 fe7e8758 Paul Brook
    for (i = 0; i < 64; i++) {
189 fe7e8758 Paul Brook
        pic[i] = qdev_get_irq_sink(nvic, i);
190 fe7e8758 Paul Brook
    }
191 9ee6e8bb pbrook
192 9ee6e8bb pbrook
    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
193 9ee6e8bb pbrook
    if (image_size < 0) {
194 dcac9679 pbrook
        image_size = load_image_targphys(kernel_filename, 0, flash_size);
195 9ee6e8bb pbrook
        lowaddr = 0;
196 9ee6e8bb pbrook
    }
197 9ee6e8bb pbrook
    if (image_size < 0) {
198 9ee6e8bb pbrook
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
199 9ee6e8bb pbrook
                kernel_filename);
200 9ee6e8bb pbrook
        exit(1);
201 9ee6e8bb pbrook
    }
202 9ee6e8bb pbrook
203 9ee6e8bb pbrook
    /* If the image was loaded at address zero then assume it is a
204 9ee6e8bb pbrook
       regular ROM image and perform the normal CPU reset sequence.
205 9ee6e8bb pbrook
       Otherwise jump directly to the entry point.  */
206 9ee6e8bb pbrook
    if (lowaddr == 0) {
207 44654490 pbrook
        env->regs[13] = ldl_phys(0);
208 44654490 pbrook
        pc = ldl_phys(4);
209 9ee6e8bb pbrook
    } else {
210 9ee6e8bb pbrook
        pc = entry;
211 9ee6e8bb pbrook
    }
212 9ee6e8bb pbrook
    env->thumb = pc & 1;
213 9ee6e8bb pbrook
    env->regs[15] = pc & ~1;
214 9ee6e8bb pbrook
215 9ee6e8bb pbrook
    /* Hack to map an additional page of ram at the top of the address
216 9ee6e8bb pbrook
       space.  This stops qemu complaining about executing code outside RAM
217 9ee6e8bb pbrook
       when returning from an exception.  */
218 dcac9679 pbrook
    cpu_register_physical_memory(0xfffff000, 0x1000,
219 dcac9679 pbrook
                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
220 9ee6e8bb pbrook
221 9ee6e8bb pbrook
    return pic;
222 9ee6e8bb pbrook
}