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