简介
本系列博客主要描述了STMF103的qemu模拟器实现,进行该项目的原因有两点: 作者在高铁上,想在STM32F103上验证一个软件框架时,如果此时掏出开发板,然后接一堆的线,旁边的人估计会投来异样的目光,特别是,当不太幸运坐在了靠近过道的位置,那就更麻烦了,估计没法进行代码开发了。因此,作者决定开发这个模拟器该项目,只要打开电脑,就可以随意的开发软件功能;第二个原因,作者也在设计STM32F103的PCB板卡,在硬件板卡还没焊接回来时,也可以提前进行产品原型的代码开发。
硬件板卡3d图
添加步骤
1. 创建stm32f103_soc.h文件
在qemu源码下添加include/hw/arm/stm32f103_soc.h文件,在文件中主要添加如下成员:
diff --git a/include/hw/arm/stm32f103_soc.h b/include/hw/arm/stm32f103_soc.h
new file mode 100644
index 00000000..182fe14b
--- /dev/null
+++ b/include/hw/arm/stm32f103_soc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2025 liang yan <yanl1229@163.com>
+ *
+ * STM32F103 SoC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#ifndef STM32F103_SOC_H
+#define STM32F103_SOC_H
+
+#include "hw/or-irq.h"
+#include "hw/arm/armv7m.h"
+
+
+#define FLASH_BASE_ADDRESS 0x8000000
+#define FLASH_SIZE (128*1024)
+#define SRAM_BASE_ADDRESS 0x20000000
+#define SRAM_SIZE (20 * 1024)
+
+#define TYPE_STM32F103_SOC "stm32f103-soc"
+#define STM32F103_SOC(obj) \
+ OBJECT_CHECK(STM32F103State, (obj), TYPE_STM32F103_SOC)
+
+typedef struct STM32F103State {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ char *kernel_filename;
+ char *cpu_type;
+ ARMv7MState armv7m;
+
+} STM32F103State;
+
+#endif
2. 创建stm32f103_soc.c文件
在qemu源码下添加hw/arm/stm32f103_soc.c文件,在文件中主要内容如下
diff --git a/hw/arm/stm32f103_soc.c b/hw/arm/stm32f103_soc.c
new file mode 100644
index 00000000..b072855e
--- /dev/null
+++ b/hw/arm/stm32f103_soc.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2025 liang yan <yanl1229@163.com>
+ *
+ * STM32F103 SoC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "hw/arm/boot.h"
+#include "hw/qdev-properties.h"
+#include "sysemu/sysemu.h"
+#include "migration/vmstate.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/stm32f103_soc.h"
+#include "sysemu/sysemu.h"
+
+static void stm32f103_soc_initfn(Object *obj)
+{
+
+ STM32F103State *s = STM32F103_SOC(obj);
+
+ sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m),
+ TYPE_ARMV7M);
+}
+
+static void stm32f103_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+ STM32F103State *s = STM32F103_SOC(dev_soc);
+ DeviceState *armv7m;
+ Error *err = NULL;
+
+ armv7m = DEVICE(&s->armv7m);
+ qdev_prop_set_uint32(armv7m, "num-irq", 68);
+ qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
+ qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ object_property_set_link(OBJECT(&s->armv7m), OBJECT(get_system_memory()),
+ "memory", &error_abort);
+ object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+}
+
+static Property stm32f103_soc_properties[] = {
+ DEFINE_PROP_STRING("kernel-filename", STM32F103State, kernel_filename),
+ DEFINE_PROP_STRING("cpu-type", STM32F103State, cpu_type),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32f103_soc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = stm32f103_soc_realize;
+ dc->props = stm32f103_soc_properties;
+}
+
+static const TypeInfo stm32f103_soc_info = {
+ .name = TYPE_STM32F103_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F103State),
+ .instance_init = stm32f103_soc_initfn,
+ .class_init = stm32f103_soc_class_init,
+};
+
+static void stm32f103_soc_types(void)
+{
+ type_register_static(&stm32f103_soc_info);
+}
+
+type_init(stm32f103_soc_types)
3. 创建开发板文件
在qemu源码下创建hw/arm/stm32f103-st-openmcu.c, 文件主要内容如下所示:
diff --git a/hw/arm/stm32f103-st-openmcu.c b/hw/arm/stm32f103-st-openmcu.c
new file mode 100644
index 00000000..d3e60021
--- /dev/null
+++ b/hw/arm/stm32f103-st-openmcu.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2025 liang yan <yanl1229@163.com>
+ *
+ * STM32F103 OpenMCU Board
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "qemu/error-report.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/stm32f103_soc.h"
+#include "hw/qdev-properties.h"
+#include "hw/arm/boot.h"
+
+static void openmcu_init(MachineState *machine)
+{
+ DeviceState *dev;
+ MemoryRegion *system_memory = get_system_memory();
+ MemoryRegion *sram = g_new(MemoryRegion, 1);
+ MemoryRegion *flash = g_new(MemoryRegion, 1);
+ MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
+
+ memory_region_init_ram(flash, NULL, "STM32F103.flash", FLASH_SIZE,
+ &error_fatal);
+ memory_region_init_alias(flash_alias, NULL, "STM32F103.flash.alias",
+ flash, 0, FLASH_SIZE);
+
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
+ memory_region_add_subregion(system_memory, 0, flash_alias);
+
+ memory_region_init_ram(sram, NULL, "STM32F103.sram", SRAM_SIZE,
+ &error_fatal);
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
+
+ dev = qdev_create(NULL, TYPE_STM32F103_SOC);
+
+ qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
+ object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal);
+
+ armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ FLASH_SIZE);
+}
+
+static void openmcu_machine_init(MachineClass *mc)
+{
+ mc->desc = "Open MCU EVK Board (STM32F103 Soc)";
+ mc->init = openmcu_init;
+}
+
+DEFINE_MACHINE("stm32f103-openmcu", openmcu_machine_init)
4. 添加编译规则
a. 修改:hw/arm/Kconfig
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index c647cf1c..85c93cdf 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -129,6 +129,10 @@ config NETDUINO2
bool
select STM32F205_SOC
+config STM32F103_ST_OPENMCU
+ bool
+ select STM32F103_SOC
+
config STM32F429_ST_DISCOVERY
bool
select STM32F429_SOC
@@ -405,6 +409,11 @@ config RASPI
select PL011 # UART
select SDHCI
+config STM32F103_SOC
+ bool
+ select ARM_V7M
+ select OR_IRQ
+
config STM32F205_SOC
bool
select ARM_V7M
b. 修改default-configs/devices/arm-softmmu.mak:
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 3a360620..1dcce679 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -46,6 +46,7 @@ CONFIG_STM32F429_ST_DISCOVERY=y
CONFIG_STM32F407_ST_DISCOVERY=y
CONFIG_STM32H743_ST_NUCLEO=y
CONFIG_STM32H750_ART_PI=y
+CONFIG_STM32F103_ST_OPENMCU=y
CONFIG_MINI2440=y
CONFIG_SMDK2416=y
CONFIG_ORANGE_PI=y
c. 修改hw/arm/Makefile.objs
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index a4eddba1..a7397383 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -36,6 +36,7 @@ obj-$(CONFIG_VERSATILEAB) += versatileab.o
obj-$(CONFIG_VEXPRESS) += vexpress.o vexpress-a9.o
obj-$(CONFIG_ZYNQ) += xilinx_zynq.o
obj-$(CONFIG_SABRELITE) += sabrelite.o
+obj-$(CONFIG_STM32F103_ST_OPENMCU) += stm32f103-st-openmcu.o
obj-$(CONFIG_STM32F429_ST_DISCOVERY) += stm32f429-st-disco.o
obj-$(CONFIG_STM32F407_ST_DISCOVERY) += stm32f407-st-disco.o
obj-$(CONFIG_STM32H743_ST_NUCLEO) += stm32h743-st-nucleo.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_OMAP) += omap1.o omap2.o
obj-$(CONFIG_STRONGARM) += strongarm.o
obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o
+obj-$(CONFIG_STM32F103_SOC) += stm32f103_soc.o
obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
obj-$(CONFIG_STM32F429_SOC) += stm32f429_soc.o
obj-$(CONFIG_STM32F407_SOC) += stm32f407_soc.o