2 * ARMV7M System emulation.
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
10 #include "qemu/osdep.h"
11 #include "hw/sysbus.h"
12 #include "hw/arm/arm.h"
13 #include "hw/loader.h"
15 #include "sysemu/qtest.h"
16 #include "qemu/error-report.h"
18 /* Bitbanded IO. Each word corresponds to a single bit. */
20 /* Get the byte address of the real memory for a bitband access. */
21 static inline uint32_t bitband_addr(void * opaque
, uint32_t addr
)
25 res
= *(uint32_t *)opaque
;
26 res
|= (addr
& 0x1ffffff) >> 5;
31 static uint32_t bitband_readb(void *opaque
, hwaddr offset
)
34 cpu_physical_memory_read(bitband_addr(opaque
, offset
), &v
, 1);
35 return (v
& (1 << ((offset
>> 2) & 7))) != 0;
38 static void bitband_writeb(void *opaque
, hwaddr offset
,
44 addr
= bitband_addr(opaque
, offset
);
45 mask
= (1 << ((offset
>> 2) & 7));
46 cpu_physical_memory_read(addr
, &v
, 1);
51 cpu_physical_memory_write(addr
, &v
, 1);
54 static uint32_t bitband_readw(void *opaque
, hwaddr offset
)
59 addr
= bitband_addr(opaque
, offset
) & ~1;
60 mask
= (1 << ((offset
>> 2) & 15));
62 cpu_physical_memory_read(addr
, &v
, 2);
63 return (v
& mask
) != 0;
66 static void bitband_writew(void *opaque
, hwaddr offset
,
72 addr
= bitband_addr(opaque
, offset
) & ~1;
73 mask
= (1 << ((offset
>> 2) & 15));
75 cpu_physical_memory_read(addr
, &v
, 2);
80 cpu_physical_memory_write(addr
, &v
, 2);
83 static uint32_t bitband_readl(void *opaque
, hwaddr offset
)
88 addr
= bitband_addr(opaque
, offset
) & ~3;
89 mask
= (1 << ((offset
>> 2) & 31));
91 cpu_physical_memory_read(addr
, &v
, 4);
92 return (v
& mask
) != 0;
95 static void bitband_writel(void *opaque
, hwaddr offset
,
101 addr
= bitband_addr(opaque
, offset
) & ~3;
102 mask
= (1 << ((offset
>> 2) & 31));
103 mask
= tswap32(mask
);
104 cpu_physical_memory_read(addr
, &v
, 4);
109 cpu_physical_memory_write(addr
, &v
, 4);
112 static const MemoryRegionOps bitband_ops
= {
114 .read
= { bitband_readb
, bitband_readw
, bitband_readl
, },
115 .write
= { bitband_writeb
, bitband_writew
, bitband_writel
, },
117 .endianness
= DEVICE_NATIVE_ENDIAN
,
120 #define TYPE_BITBAND "ARM,bitband-memory"
121 #define BITBAND(obj) OBJECT_CHECK(BitBandState, (obj), TYPE_BITBAND)
125 SysBusDevice parent_obj
;
132 static int bitband_init(SysBusDevice
*dev
)
134 BitBandState
*s
= BITBAND(dev
);
136 memory_region_init_io(&s
->iomem
, OBJECT(s
), &bitband_ops
, &s
->base
,
137 "bitband", 0x02000000);
138 sysbus_init_mmio(dev
, &s
->iomem
);
142 static void armv7m_bitband_init(void)
146 dev
= qdev_create(NULL
, TYPE_BITBAND
);
147 qdev_prop_set_uint32(dev
, "base", 0x20000000);
148 qdev_init_nofail(dev
);
149 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 0, 0x22000000);
151 dev
= qdev_create(NULL
, TYPE_BITBAND
);
152 qdev_prop_set_uint32(dev
, "base", 0x40000000);
153 qdev_init_nofail(dev
);
154 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 0, 0x42000000);
159 static void armv7m_reset(void *opaque
)
161 ARMCPU
*cpu
= opaque
;
166 /* Init CPU and memory for a v7-M based board.
167 mem_size is in bytes.
168 Returns the NVIC array. */
170 DeviceState
*armv7m_init(MemoryRegion
*system_memory
, int mem_size
, int num_irq
,
171 const char *kernel_filename
, const char *cpu_model
)
180 MemoryRegion
*hack
= g_new(MemoryRegion
, 1);
182 if (cpu_model
== NULL
) {
183 cpu_model
= "cortex-m3";
185 cpu
= cpu_arm_init(cpu_model
);
187 fprintf(stderr
, "Unable to find CPU definition\n");
192 armv7m_bitband_init();
194 nvic
= qdev_create(NULL
, "armv7m_nvic");
195 qdev_prop_set_uint32(nvic
, "num-irq", num_irq
);
197 qdev_init_nofail(nvic
);
198 sysbus_connect_irq(SYS_BUS_DEVICE(nvic
), 0,
199 qdev_get_gpio_in(DEVICE(cpu
), ARM_CPU_IRQ
));
201 #ifdef TARGET_WORDS_BIGENDIAN
207 if (!kernel_filename
&& !qtest_enabled()) {
208 fprintf(stderr
, "Guest image must be specified (using -kernel)\n");
212 if (kernel_filename
) {
213 image_size
= load_elf(kernel_filename
, NULL
, NULL
, &entry
, &lowaddr
,
214 NULL
, big_endian
, EM_ARM
, 1);
215 if (image_size
< 0) {
216 image_size
= load_image_targphys(kernel_filename
, 0, mem_size
);
219 if (image_size
< 0) {
220 error_report("Could not load kernel '%s'", kernel_filename
);
225 /* Hack to map an additional page of ram at the top of the address
226 space. This stops qemu complaining about executing code outside RAM
227 when returning from an exception. */
228 memory_region_init_ram(hack
, NULL
, "armv7m.hack", 0x1000, &error_fatal
);
229 vmstate_register_ram_global(hack
);
230 memory_region_add_subregion(system_memory
, 0xfffff000, hack
);
232 qemu_register_reset(armv7m_reset
, cpu
);
236 static Property bitband_properties
[] = {
237 DEFINE_PROP_UINT32("base", BitBandState
, base
, 0),
238 DEFINE_PROP_END_OF_LIST(),
241 static void bitband_class_init(ObjectClass
*klass
, void *data
)
243 DeviceClass
*dc
= DEVICE_CLASS(klass
);
244 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
246 k
->init
= bitband_init
;
247 dc
->props
= bitband_properties
;
250 static const TypeInfo bitband_info
= {
251 .name
= TYPE_BITBAND
,
252 .parent
= TYPE_SYS_BUS_DEVICE
,
253 .instance_size
= sizeof(BitBandState
),
254 .class_init
= bitband_class_init
,
257 static void armv7m_register_types(void)
259 type_register_static(&bitband_info
);
262 type_init(armv7m_register_types
)