This patch adds support for the emulation of different density lines (low, medium, and high). A new class property stm32f100-soc.density= has been introduced to allow users to state the desired configuration. That property is recognized by a new machine, stm32f1-generic. The SOC is configured according to the following:
density=low 32 KB FLASH, 2 SPIs density=medium 128 KB FLASH, 2 SPIs density=high 512 KB FLASH, 3 SPIs With this code change we should be able to introduce richer features to STM32F100, such as support for FSMC (so that a machine with more RAM capacity can be properly emulated). FSMC is supported on high density line devices only. Signed-off-by: Lucas C. Villa Real <lu...@osdyne.com> --- configs/devices/arm-softmmu/default.mak | 1 + docs/system/arm/stm32.rst | 14 ++++ hw/arm/Kconfig | 6 ++ hw/arm/meson.build | 1 + hw/arm/stm32f100_soc.c | 92 +++++++++++++++++++++---- hw/arm/stm32f1_generic.c | 70 +++++++++++++++++++ hw/arm/stm32vldiscovery.c | 3 +- include/hw/arm/stm32f100_soc.h | 18 ++++- 8 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 hw/arm/stm32f1_generic.c diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak index 980c48a7d9..4f0f2e99c0 100644 --- a/configs/devices/arm-softmmu/default.mak +++ b/configs/devices/arm-softmmu/default.mak @@ -19,6 +19,7 @@ CONFIG_ARM_VIRT=y # CONFIG_NSERIES=n # CONFIG_STELLARIS=n # CONFIG_STM32VLDISCOVERY=n +# CONFIG_STM32F1_GENERIC=n # CONFIG_REALVIEW=n # CONFIG_VERSATILE=n # CONFIG_VEXPRESS=n diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst index d7265b763d..d0a3b1a7eb 100644 --- a/docs/system/arm/stm32.rst +++ b/docs/system/arm/stm32.rst @@ -10,6 +10,12 @@ The STM32F1 series is based on ARM Cortex-M3 core. The following machines are based on this chip : - ``stm32vldiscovery`` STM32VLDISCOVERY board with STM32F100RBT6 microcontroller +- ``stm32f1-generic`` Generic STM32F1 board supporting low, medium and high + density devices. Low-density emulates a 32KB FLASH; + medium-density emulates a 128KB FLASH; high-density + emulates a 512KB FLASH. The density also affects the + number of peripherals exposed by QEMU for the emulated + device. See ``Boot options`` below for more details. The STM32F2 series is based on ARM Cortex-M3 core. The following machines are based on this chip : @@ -65,3 +71,11 @@ firmware. Example: .. code-block:: bash $ qemu-system-arm -M stm32vldiscovery -kernel firmware.bin + +Additionally, the ``stm32f1-generic`` board supports the ``density`` option +to select the device density line. The following values are supported: +``low``, ``medium``, ``high``. Example: + +.. code-block:: bash + + $ qemu-system-arm -M stm32f1-generic -global stm32f100-soc.density=medium ... \ No newline at end of file diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 2159de3ce6..822441945c 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -301,6 +301,12 @@ config STM32VLDISCOVERY depends on TCG && ARM select STM32F100_SOC +config STM32F1_GENERIC + bool + default y + depends on TCG && ARM + select STM32F100_SOC + config STRONGARM bool select PXA2XX diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 870ec67376..f88b5fe3c8 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -23,6 +23,7 @@ arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c')) arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c')) arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c')) arm_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c')) +arm_ss.add(when: 'CONFIG_STM32F1_GENERIC', if_true: files('stm32f1_generic.c')) arm_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c')) arm_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c')) arm_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c index f7b344ba9f..c157ffd644 100644 --- a/hw/arm/stm32f100_soc.c +++ b/hw/arm/stm32f100_soc.c @@ -38,10 +38,11 @@ static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40013800, 0x40004400, 0x40004800 }; -static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800 }; +static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800, + 0x40003C00 }; static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39}; -static const int spi_irq[STM_NUM_SPIS] = {35, 36}; +static const int spi_irq[STM_NUM_SPIS] = {35, 36, 51}; static void stm32f100_soc_initfn(Object *obj) { @@ -50,17 +51,21 @@ static void stm32f100_soc_initfn(Object *obj) object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); + /* + * All density lines feature the same number of USARTs, so they can be + * initialized in this function. The number of SPIs is density-dependent, + * though, so SPIs are initialized in stm32f100_soc_realize(). + */ for (i = 0; i < STM_NUM_USARTS; i++) { object_initialize_child(obj, "usart[*]", &s->usart[i], TYPE_STM32F2XX_USART); } - for (i = 0; i < STM_NUM_SPIS; i++) { - object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI); - } - s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0); + + /* Default density. May be overridden by the machine or cmdline option */ + s->density = STM32F100_DENSITY_HIGH; } static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) @@ -70,6 +75,17 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) SysBusDevice *busdev; int i; + if (s->density == STM32F100_DENSITY_HIGH) { + s->num_spis = 3; + s->flash_size = FLASH_SIZE_HD; + } else if (s->density == STM32F100_DENSITY_MEDIUM) { + s->num_spis = 2; + s->flash_size = FLASH_SIZE_MD; + } else { + s->num_spis = 2; + s->flash_size = FLASH_SIZE_LD; + } + MemoryRegion *system_memory = get_system_memory(); /* @@ -101,9 +117,10 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) * Flash starts at 0x08000000 and then is aliased to boot memory at 0x0 */ memory_region_init_rom(&s->flash, OBJECT(dev_soc), "STM32F100.flash", - FLASH_SIZE, &error_fatal); + s->flash_size, &error_fatal); memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc), - "STM32F100.flash.alias", &s->flash, 0, FLASH_SIZE); + "STM32F100.flash.alias", &s->flash, 0, + s->flash_size); memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash); memory_region_add_subregion(system_memory, 0, &s->flash_alias); @@ -137,8 +154,11 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i])); } - /* SPI 1 and 2 */ - for (i = 0; i < STM_NUM_SPIS; i++) { + /* Initialize all SPIs supported by the selected density line */ + for (i = 0; i < s->num_spis; i++) { + object_initialize_child(OBJECT(dev_soc), "spi[*]", &s->spi[i], + TYPE_STM32F2XX_SPI); + dev = DEVICE(&(s->spi[i])); if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; @@ -153,9 +173,14 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("timer[4]", 0x40000800, 0x400); create_unimplemented_device("timer[6]", 0x40001000, 0x400); create_unimplemented_device("timer[7]", 0x40001400, 0x400); + create_unimplemented_device("timer[12]", 0x40001800, 0x400); + create_unimplemented_device("timer[13]", 0x40001C00, 0x400); + create_unimplemented_device("timer[14]", 0x40002000, 0x400); create_unimplemented_device("RTC", 0x40002800, 0x400); create_unimplemented_device("WWDG", 0x40002C00, 0x400); create_unimplemented_device("IWDG", 0x40003000, 0x400); + create_unimplemented_device("UART4", 0x40004C00, 0x400); + create_unimplemented_device("UART5", 0x40005000, 0x400); create_unimplemented_device("I2C1", 0x40005400, 0x400); create_unimplemented_device("I2C2", 0x40005800, 0x400); create_unimplemented_device("BKP", 0x40006C00, 0x400); @@ -169,12 +194,15 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("GPIOC", 0x40011000, 0x400); create_unimplemented_device("GPIOD", 0x40011400, 0x400); create_unimplemented_device("GPIOE", 0x40011800, 0x400); + create_unimplemented_device("GPIOF", 0x40011C00, 0x400); + create_unimplemented_device("GPIOG", 0x40012000, 0x400); create_unimplemented_device("ADC1", 0x40012400, 0x400); create_unimplemented_device("timer[1]", 0x40012C00, 0x400); create_unimplemented_device("timer[15]", 0x40014000, 0x400); create_unimplemented_device("timer[16]", 0x40014400, 0x400); create_unimplemented_device("timer[17]", 0x40014800, 0x400); - create_unimplemented_device("DMA", 0x40020000, 0x400); + create_unimplemented_device("DMA1", 0x40020000, 0x400); + create_unimplemented_device("DMA2", 0x40020400, 0x400); create_unimplemented_device("RCC", 0x40021000, 0x400); create_unimplemented_device("Flash Int", 0x40022000, 0x400); create_unimplemented_device("CRC", 0x40023000, 0x400); @@ -185,12 +213,50 @@ static Property stm32f100_soc_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void stm32f100_soc_class_init(ObjectClass *klass, void *data) +static char *stm32f100_get_density(Object *obj, Error **errp) { - DeviceClass *dc = DEVICE_CLASS(klass); + STM32F100State *s = STM32F100_SOC(obj); + + switch (s->density) { + case STM32F100_DENSITY_LOW: + return g_strdup("low"); + case STM32F100_DENSITY_MEDIUM: + return g_strdup("medium"); + case STM32F100_DENSITY_HIGH: + return g_strdup("high"); + default: + g_assert_not_reached(); + } +} + +static void stm32f100_set_density(Object *obj, const char *value, Error **errp) +{ + STM32F100State *s = STM32F100_SOC(obj); + + if (!strcmp(value, "low")) { + s->density = STM32F100_DENSITY_LOW; + } else if (!strcmp(value, "medium")) { + s->density = STM32F100_DENSITY_MEDIUM; + } else if (!strcmp(value, "high")) { + s->density = STM32F100_DENSITY_HIGH; + } else { + error_setg(errp, "Invalid density value '%s'", value); + error_append_hint(errp, "Valid values: 'low', 'medium', 'high'\n"); + } +} + +static void stm32f100_soc_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = stm32f100_soc_realize; device_class_set_props(dc, stm32f100_soc_properties); + + object_class_property_add_str(oc, "density", stm32f100_get_density, + stm32f100_set_density); + object_class_property_set_description(oc, "density", + "Set the STM32F100 density line device. " + "Valid values are 'low', 'medium', and 'high' (default)."); } static const TypeInfo stm32f100_soc_info = { diff --git a/hw/arm/stm32f1_generic.c b/hw/arm/stm32f1_generic.c new file mode 100644 index 0000000000..63d2a58bdc --- /dev/null +++ b/hw/arm/stm32f1_generic.c @@ -0,0 +1,70 @@ +/* + * ST generic STM32F1 board + * + * Copyright (c) 2023 Lucas C. Villa Real <lu...@osdyne.com> + * Copyright (c) 2021 Alexandre Iooss <erdn...@crans.org> + * Copyright (c) 2014 Alistair Francis <alist...@alistair23.me> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-clock.h" +#include "qemu/error-report.h" +#include "hw/arm/stm32f100_soc.h" +#include "hw/arm/boot.h" + +/* Main SYSCLK frequency in Hz (24MHz) */ +#define SYSCLK_FRQ 24000000ULL + +static void stm32f1_generic_init(MachineState *machine) +{ + STM32F100State *s; + DeviceState *dev; + Clock *sysclk; + + /* This clock doesn't need migration because it is fixed-frequency */ + sysclk = clock_new(OBJECT(machine), "SYSCLK"); + clock_set_hz(sysclk, SYSCLK_FRQ); + + /* + * Note that we don't set the "density" property so that the default + * value ("high") can be changed via "-global stm32f100-soc.density=..." + */ + dev = qdev_new(TYPE_STM32F100_SOC); + qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); + qdev_connect_clock_in(dev, "sysclk", sysclk); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + s = STM32F100_SOC(OBJECT(dev)); + armv7m_load_kernel(ARM_CPU(first_cpu), + machine->kernel_filename, + 0, s->flash_size); +} + +static void stm32f1_generic_machine_init(MachineClass *mc) +{ + mc->desc = "STM32F1 generic (Cortex-M3)"; + mc->init = stm32f1_generic_init; +} + +DEFINE_MACHINE("stm32f1-generic", stm32f1_generic_machine_init) diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c index 67675e952f..3c4bffe5d4 100644 --- a/hw/arm/stm32vldiscovery.c +++ b/hw/arm/stm32vldiscovery.c @@ -47,13 +47,14 @@ static void stm32vldiscovery_init(MachineState *machine) clock_set_hz(sysclk, SYSCLK_FRQ); dev = qdev_new(TYPE_STM32F100_SOC); + qdev_prop_set_string(dev, "density", "medium"); qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3")); qdev_connect_clock_in(dev, "sysclk", sysclk); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, - 0, FLASH_SIZE); + 0, FLASH_SIZE_MD); } static void stm32vldiscovery_machine_init(MachineClass *mc) diff --git a/include/hw/arm/stm32f100_soc.h b/include/hw/arm/stm32f100_soc.h index 40cd415b28..5305e342e3 100644 --- a/include/hw/arm/stm32f100_soc.h +++ b/include/hw/arm/stm32f100_soc.h @@ -34,14 +34,24 @@ #define TYPE_STM32F100_SOC "stm32f100-soc" OBJECT_DECLARE_SIMPLE_TYPE(STM32F100State, STM32F100_SOC) +/* Definitions for high-density value line devices */ #define STM_NUM_USARTS 3 -#define STM_NUM_SPIS 2 +#define STM_NUM_SPIS 3 #define FLASH_BASE_ADDRESS 0x08000000 -#define FLASH_SIZE (128 * 1024) +#define FLASH_SIZE_LD (32 * 1024) +#define FLASH_SIZE_MD (128 * 1024) +#define FLASH_SIZE_HD (512 * 1024) #define SRAM_BASE_ADDRESS 0x20000000 #define SRAM_SIZE (8 * 1024) +/* Supported density value lines */ +typedef enum { + STM32F100_DENSITY_LOW, + STM32F100_DENSITY_MEDIUM, + STM32F100_DENSITY_HIGH, +} STM32F100Density; + struct STM32F100State { /*< private >*/ SysBusDevice parent_obj; @@ -60,6 +70,10 @@ struct STM32F100State { Clock *sysclk; Clock *refclk; + + STM32F100Density density; + uint8_t num_spis; + uint32_t flash_size; }; #endif -- 2.39.2 (Apple Git-143)