diff mbox

[RFC] STM32 MCUs support

Message ID CC1E36B0-9467-4FB1-9E57-A95849CA1020@livius.net
State New
Headers show

Commit Message

Liviu Ionescu June 17, 2015, 8:15 p.m. UTC
# Goal

Create a framework that allows to easily add new STM32 MCUs. 

Once detailes cleared, the same template will be used for other MCUs,
from other vendors.

# Implementation

All STM32 MCU objects are derived from a common "stm32-mcu" object, that
implements the object construction logic, based on some capabilities
tables.

The capabilities are split between STM32 specific and Cortex-M specific.

The actual table includes pointers to these structures and memory sizes.

typedef struct {

    const char *name; /* CMSIS device name */

    const unsigned int flash_size_kb; /* size of main program area, in KB */
    const unsigned int sram_size_kb; /* size of main RAM area, in KB */

    const CortexMCapabilities *core;
    const STM32Capabilities *stm32;

} STM32PartInfo;

With such a structure it is quite simple to define new devices that differ 
only by memory sizes using existing definitions.

The capabilities include most MCU specifics, but the current implementation
support only RCC, Flash & GPIOs. More to come, as needed.


# Usage

The STM32-H103 board instantiates the MCU with the following code:

    DeviceState *mcu = qdev_alloc(NULL, TYPE_STM32F103RB);
    {
        STM32_DEVICE_GET_CLASS(mcu)->construct(OBJECT(mcu), machine);

        /* Set the board specific oscillator frequencies. */
        qdev_prop_set_uint32(mcu, "hse-freq-hz", 8000000); /* 8.0 MHz */
        qdev_prop_set_uint32(mcu, "lse-freq-hz", 32768); /* 32 KHz */
    }
    qdev_realize(mcu);

This invocation uses the custom constructors mechanism to pass 
initialisation data to parent classes.

The properties are internally forwarded to the proper peripheral.

The current code runs without problems the projects generated by the
GNU ARM Eclipse wizards, including the blinky versions (that use
the gpio-led object mentioned in another post.

# Credits

Many thanks to Andre Beckus for the inspiration.
diff mbox

Patch

diff --git a/hw/arm/stm32-mcu.c b/hw/arm/stm32-mcu.c
new file mode 100644
index 0000000..64a711c
--- /dev/null
+++ b/hw/arm/stm32-mcu.c
@@ -0,0 +1,292 @@ 
+/*
+ * STM32 Cortex-M device emulation.
+ *
+ * Copyright (c) 2014 Liviu Ionescu
+ * Copyright (c) 2010 Andre Beckus
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#include "hw/arm/stm32-mcu.h"
+
+#if defined(CONFIG_VERBOSE)
+#include "verbosity.h"
+#endif
+
+/* ----- Private ----------------------------------------------------------- */
+
+/**
+ * Create children GPIO nodes. Public names are "/machine/stm32/gpio[%c]".
+ */
+static void create_gpio(STM32MCUState *state, stm32_gpio_index_t index,
+        const STM32Capabilities *capabilities)
+{
+    DeviceState *dev;
+    STM32SysBusDevice *sbd;
+    STM32GPIOState *gdev;
+
+    dev = qdev_create(NULL, TYPE_STM32_GPIO);
+    sbd = STM32_SYS_BUS_DEVICE_STATE(dev);
+    sbd->capabilities = capabilities;
+
+    gdev = STM32_GPIO_STATE(dev);
+    gdev->port_index = index;
+    gdev->rcc = STM32_RCC_STATE(state->rcc);
+
+    state->gpio[index] = dev;
+
+    char child_name[10];
+    snprintf(child_name, sizeof(child_name), "gpio[%c]", 'a' + index);
+
+    object_property_add_child(state->container, child_name, OBJECT(dev), NULL);
+}
+
+/**
+ * Constructor for all STM32 devices, based on capabilities.
+ *
+ * Alias the flash memory to 0x08000000.
+ *
+ * TODO: define the special CCM region for the models that include it.
+ */
+static void stm32_mcu_construct_callback(Object *obj,
+        const STM32Capabilities *capabilities,
+        const CortexMCapabilities *core_capabilities, const int flash_size_kb,
+        const int sram_size_kb, MachineState *machine)
+{
+    qemu_log_function_name();
+
+    /* Call parent constructor */
+    CORTEXM_MCU_GET_CLASS(obj)->construct(obj, core_capabilities, flash_size_kb,
+            sram_size_kb, machine);
+
+    STM32MCUState *state = STM32_MCU_STATE(obj);
+    assert(capabilities != NULL);
+    state->capabilities = capabilities;
+
+    const char *family;
+    switch (capabilities->family) {
+    case STM32_FAMILY_F1:
+        family = "F1";
+        break;
+    case STM32_FAMILY_F2:
+        family = "F2";
+        break;
+    case STM32_FAMILY_F3:
+        family = "F3";
+        break;
+    case STM32_FAMILY_F4:
+        family = "F4";
+        break;
+    case STM32_FAMILY_L1:
+        family = "L1";
+        break;
+    default:
+        family = "unknown";
+    }
+    qemu_log_mask(LOG_TRACE, "STM32 Family: %s\n", family);
+
+    /* Devices will be addressed below "/machine/stm32". */
+    state->container = container_get(qdev_get_machine(), "/stm32");
+
+    DeviceState *dev;
+    STM32SysBusDevice *sbd;
+
+    /* RCC */
+    {
+        state->rcc = qdev_create(NULL, TYPE_STM32_RCC);
+        dev = DEVICE(state->rcc);
+
+        /* Copy capabilities into internal objects. */
+        sbd = STM32_SYS_BUS_DEVICE_STATE(state->rcc);
+        sbd->capabilities = capabilities;
+
+        /* Copy internal oscillator frequencies from capabilities. */
+        qdev_prop_set_uint32(dev, "hsi-freq-hz",
+                sbd->capabilities->hsi_freq_hz);
+        qdev_prop_set_uint32(dev, "lsi-freq-hz",
+                sbd->capabilities->lsi_freq_hz);
+
+        /* Alias RCC properties to MCU, to hide internal details. */
+        object_property_add_alias(obj, "hse-freq-hz", OBJECT(dev),
+                "hse-freq-hz", NULL);
+        object_property_add_alias(obj, "lse-freq-hz", OBJECT(dev),
+                "lse-freq-hz", NULL);
+
+        /* RCC will be named "/machine/stm32/rcc" */
+        object_property_add_child(state->container, "rcc", OBJECT(state->rcc),
+        NULL);
+    }
+
+    /* FLASH */
+    {
+        state->flash = qdev_create(NULL, TYPE_STM32_FLASH);
+        sbd = STM32_SYS_BUS_DEVICE_STATE(state->flash);
+        sbd->capabilities = capabilities;
+
+        /* FLASH will be named "/machine/stm32/flash" */
+        object_property_add_child(state->container, "flash",
+                OBJECT(state->flash), NULL);
+    }
+
+    /* GPIOA */
+    if (capabilities->has_gpioa) {
+        create_gpio(state, STM32_GPIO_PORT_A, capabilities);
+    }
+
+    /* GPIOB */
+    if (capabilities->has_gpiob) {
+        create_gpio(state, STM32_GPIO_PORT_B, capabilities);
+    }
+
+    /* GPIOC */
+    if (capabilities->has_gpioc) {
+        create_gpio(state, STM32_GPIO_PORT_C, capabilities);
+    }
+
+    /* GPIOD */
+    if (capabilities->has_gpiod) {
+        create_gpio(state, STM32_GPIO_PORT_D, capabilities);
+    }
+
+    /* GPIOE */
+    if (capabilities->has_gpioe) {
+        create_gpio(state, STM32_GPIO_PORT_E, capabilities);
+    }
+
+    /* GPIOF */
+    if (capabilities->has_gpiof) {
+        create_gpio(state, STM32_GPIO_PORT_F, capabilities);
+    }
+
+    /* GPIOG */
+    if (capabilities->has_gpiog) {
+        create_gpio(state, STM32_GPIO_PORT_G, capabilities);
+    }
+
+    /* TODO: add more devices. */
+}
+
+static void stm32_mcu_realize_callback(DeviceState *dev, Error **errp)
+{
+    qemu_log_function_name();
+
+    /* Call the parent realize(). */
+    DeviceClass *parent_class = DEVICE_CLASS(
+            object_class_get_parent(object_class_by_name(TYPE_STM32_MCU)));
+    Error *local_err = NULL;
+    parent_class->realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    STM32MCUState *state = STM32_MCU_STATE(dev);
+
+    /* Propagate realize() to children. */
+
+    /* RCC */
+    qdev_realize(DEVICE(state->rcc));
+
+    /* FLASH */
+    qdev_realize(DEVICE(state->flash));
+
+    /* GPIO[A-G] */
+    for (int i = 0; i < STM32_MAX_GPIO; ++i) {
+        /* Realize all initialised GPIOs */
+        if (state->gpio[i]) {
+            qdev_realize(DEVICE(state->gpio[i]));
+        }
+    }
+}
+
+/**
+ * Virtual function, overriding (in fact extending) the Cortex-M code.
+ */
+static void stm32_mcu_memory_regions_create_callback(DeviceState *dev)
+{
+    qemu_log_function_name();
+
+    /* Create the parent (Cortex-M) memory regions */
+    CortexMClass *parent_class = CORTEXM_MCU_CLASS(
+            object_class_by_name(TYPE_CORTEXM_MCU));
+    parent_class->memory_regions_create(dev);
+
+    /**
+     * The STM32 family stores its Flash memory at some base address in memory
+     * (0x08000000 for medium density devices), and then aliases it to the
+     * boot memory space, which starts at 0x00000000 (the "System Memory" can
+     * also be aliased to 0x00000000, but this is not implemented here).
+     * The processor executes the code in the aliased memory at 0x00000000.
+     * We need to make a QEMU alias so that reads in the 0x08000000 area
+     * are passed through to the 0x00000000 area. Note that this is the
+     * opposite of real hardware, where the memory at 0x00000000 passes
+     * reads through the "real" flash memory at 0x08000000, but it works
+     * the same either way.
+     */
+    CortexMState *cm_state = CORTEXM_MCU_STATE(dev);
+    int flash_size = cm_state->flash_size_kb * 1024;
+
+    /* Allocate a new region for the alias */
+    MemoryRegion *flash_alias_mem = g_malloc(sizeof(MemoryRegion));
+
+    /* Initialise the new region */
+    memory_region_init_alias(flash_alias_mem, NULL, "stm32-mem-flash-alias",
+            &cm_state->flash_mem, 0, flash_size);
+    memory_region_set_readonly(flash_alias_mem, true);
+
+    /* Alias it as the STM specific 0x08000000 */
+    memory_region_add_subregion(get_system_memory(), 0x08000000,
+            flash_alias_mem);
+}
+
+static Property stm32_mcu_properties[] = {
+    /* TODO: add STM32 specific properties */
+    DEFINE_PROP_END_OF_LIST(), /**/
+};
+
+static void stm32_mcu_class_init_callback(ObjectClass *klass, void *data)
+{
+    STM32MCUClass *st_class = STM32_MCU_CLASS(klass);
+    st_class->construct = stm32_mcu_construct_callback;
+
+    CortexMClass *cm_class = CORTEXM_MCU_CLASS(klass);
+    cm_class->memory_regions_create = stm32_mcu_memory_regions_create_callback;
+
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = stm32_mcu_realize_callback;
+    dc->props = stm32_mcu_properties;
+}
+
+static const TypeInfo stm32_mcu_type_info = {
+    .abstract = true,
+    .name = TYPE_STM32_MCU,
+    .parent = TYPE_CORTEXM_MCU,
+    .instance_size = sizeof(STM32MCUState),
+    .class_init = stm32_mcu_class_init_callback,
+    .class_size = sizeof(STM32MCUClass) /**/
+};
+
+/* ----- Type inits. ----- */
+
+static void stm32_type_init()
+{
+    type_register_static(&stm32_mcu_type_info);
+}
+
+#if defined(CONFIG_GNU_ARM_ECLIPSE)
+type_init(stm32_type_init);
+#endif
+
+/* ------------------------------------------------------------------------- */
+
diff --git a/hw/arm/stm32-mcus.c b/hw/arm/stm32-mcus.c
new file mode 100644
index 0000000..c0e32af
--- /dev/null
+++ b/hw/arm/stm32-mcus.c
@@ -0,0 +1,479 @@ 
+/*
+ * STM32 Cortex-M devices emulation.
+ *
+ * Copyright (c) 2014 Liviu Ionescu
+ * Copyright (c) 2010 Andre Beckus
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#include "hw/arm/stm32-mcus.h"
+#include "hw/arm/cortexm-mcu.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
+
+#if defined(CONFIG_VERBOSE)
+#include "verbosity.h"
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * Define all STM32 MCUs, based on table capabilities.
+ *
+ * To easily reuse the definitions, each line includes a pointer
+ * to the core capabilities and a pointer to the stm32 capabilities.
+ * This greatly simplify adding definition that differ only in memory size.
+ */
+
+/*
+ * - Low-density devices are STM32F101xx, STM32F102xx and STM32F103xx
+ * microcontrollers where the Flash memory density ranges between 16
+ * and 32 Kbytes.
+ * - Medium-density devices are STM32F101xx, STM32F102xx and STM32F103xx
+ * microcontrollers where the Flash memory density ranges between 64
+ * and 128 Kbytes.
+ * - High-density devices are STM32F101xx and STM32F103xx microcontrollers
+ * where the Flash memory density ranges between 256 and 512 Kbytes.
+ * - XL-density devices are STM32F101xx and STM32F103xx microcontrollers
+ * where the Flash memory density ranges between 768 Kbytes and 1 Mbyte.
+ * - Connectivity line devices are STM32F105xx and STM32F107xx
+ * microcontrollers.
+ */
+
+/*
+ * Interrupts:
+ *
+ * - F1
+ *   - CL: 68
+ *   - [LMHX]D: 60
+ * - F4
+ *   - TBD
+ */
+
+/*
+ * STM32 pin count and package encoding (first char after number):
+ *
+ * I = BGA/LQFP 176
+ * V = LQFP/UFBGA 100
+ * Z = LQFP/UFPGA/UFBGA 144, WLCSP 143
+ * B = LQFP 208
+ * R = LQFP 64
+ * N = TFBGA
+ * A = UFBGA 169, WLCSP 168
+ * C = UFQFPN 48, WLCSP 49
+ * M = WLCSP 81
+ * O = WLCSP 90
+ */
+
+/*
+ * STM32 Flash sizes encoding (second char after number):
+ *
+ * 8 = 64K
+ * B = 128K
+ * C = 256K
+ * E = 512K
+ * F = 768K
+ * G = 1024K
+ * I = 2048K
+ */
+
+static const STM32Capabilities stm32f103x8b = {
+
+    .family = STM32_FAMILY_F1,
+    .f1 = {
+        .is_md = true },
+
+    .hsi_freq_hz = 8000000,
+    .lsi_freq_hz = 40000,
+    .has_rcc = true,
+    .has_pwr = true,
+    .has_rtc = true,
+    .num_bkp = 20,
+
+    .has_crc = true,
+    .has_exti = true,
+    .has_dma1 = true,
+    .num_dma1 = 7,
+    .has_ac_tim1 = true,
+    .has_gp1_tim2 = true,
+    .has_gp1_tim3 = true,
+    .has_gp1_tim4 = true,
+    .has_iwdg = true,
+    .has_wwdg = true,
+    .has_i2c1 = true,
+    .has_i2c2 = true,
+    .has_usart1 = true, /* 4.5Mb/s */
+    .has_usart2 = true, /* 2.25 Mb/s */
+    .has_usart3 = true, /* 2.25 Mb/s */
+    .has_spi1 = true,
+    .has_spi2 = true,
+    .has_bx_can1 = true,
+    .has_usb_fs = true,
+
+    .has_gpioa = true,
+    .has_gpiob = true,
+    .has_gpioc = true,
+    .has_gpiod = true,
+    .has_gpioe = true,
+
+    .has_adc1 = true, /* 12-bits, 16-ch */
+    .has_adc2 = true, /* 12-bits, 16-ch */
+
+    .has_ts = 1, /* ADC12_IN16 */
+};
+
+static const STM32Capabilities stm32f10_57_xx = {
+
+    .family = STM32_FAMILY_F1,
+    .f1 = {
+        .is_cl = true },
+
+    .hsi_freq_hz = 8000000,
+    .lsi_freq_hz = 40000,
+    .has_rcc = true,
+    .has_pwr = true,
+    .has_rtc = true,
+
+    .has_crc = true,
+    .has_exti = true,
+    .num_exti = 20,
+    .has_dma1 = true,
+    .num_dma1 = 7,
+    .has_dma2 = true,
+    .num_dma2 = 5,
+    .has_ac_tim1 = true,
+    .has_gp1_tim2 = true,
+    .has_gp1_tim3 = true,
+    .has_gp1_tim4 = true,
+    .has_gp1_tim5 = true,
+    .has_bc_tim6 = true,
+    .has_bc_tim7 = true,
+    .has_iwdg = true,
+    .has_wwdg = true,
+    .has_i2c1 = true,
+    .has_i2c2 = true,
+    .has_usart1 = true,
+    .has_usart2 = true,
+    .has_usart3 = true,
+    .has_uart4 = true,
+    .has_uart5 = true,
+    .has_spi1 = true,
+    .has_spi2 = true,
+    .has_spi3 = true,
+    .has_i2s1 = true,
+    .has_i2s2 = true,
+    .has_eth = true, /* 107 only */
+    .has_can1 = true,
+    .has_can2 = true,
+    .has_usb_otg_fs = true,
+    .has_gpioa = true,
+    .has_gpiob = true,
+    .has_gpioc = true,
+    .has_gpiod = true,
+    .has_gpioe = true,
+    .has_adc1 = true,
+    .has_adc2 = true,
+    .has_dac1 = true,
+    .has_dac2 = true,
+    .has_ts = true, /* ADC1_IN16 */
+};
+
+static const STM32Capabilities stm32l15_12_xd = {
+
+    .family = STM32_FAMILY_L1,
+
+    .hsi_freq_hz = 16000000,
+    .lsi_freq_hz = 37000,
+    .has_rcc = true,
+    .has_rtc = true,
+    .eeprom_size_kb = 12,
+    .num_bkp = 128,
+
+    .has_gpioa = true,
+    .has_gpiob = true,
+    .has_gpioc = true,
+    .has_gpiod = true,
+    .has_gpioe = true,
+    .has_gpiof = true,
+    .has_gpiog = true,
+    .has_gpioh = true,
+    .has_exti = true,
+    .num_exti = 24,
+    .has_fsmc = true,
+    .has_dma = true,
+    .num_dma = 12,
+    .has_adc = true, /* 12-bits, 40-ch */
+    .has_ts = true, /* ADC_IN16 */
+    .has_dac1 = true,
+    .has_dac2 = true,
+    .has_gp1_tim2 = true,
+    .has_gp1_tim3 = true,
+    .has_gp1_tim4 = true,
+    .has_gp1_tim5 = true,
+    .has_bc_tim6 = true,
+    .has_bc_tim7 = true,
+    .has_gp2_tim9 = true,
+    .has_gp3_tim10 = true,
+    .has_gp3_tim11 = true,
+    .has_iwdg = true,
+    .has_wwdg = true,
+    .has_i2c1 = true,
+    .has_i2c2 = true,
+    .has_usart1 = true,
+    .has_usart2 = true,
+    .has_usart3 = true,
+    .has_uart4 = true,
+    .has_uart5 = true,
+    .has_spi1 = true,
+    .has_spi2 = true,
+    .has_spi3 = true,
+    .has_i2s1 = true,
+    .has_i2s2 = true,
+    .has_sdio = true,
+    .has_usb_fs = true,
+    .has_crc = true,
+
+/*
+ * +LCD
+ * + comparators
+ * + touch sensing
+ */
+};
+
+static const CortexMCapabilities stm32f0xx_core = {
+    .cortexm_model = CORTEX_M0,
+    .has_mpu = false, /* itm? irqs? */
+    .nvic_bits = 4, /**/
+};
+
+static const CortexMCapabilities stm32f100_core = {
+    .cortexm_model = CORTEX_M3,
+    .has_mpu = true,
+    .has_itm = true,
+    .num_irq = 60,
+    .nvic_bits = 4, /**/
+};
+
+static const CortexMCapabilities stm32f1xx_core = {
+    .cortexm_model = CORTEX_M3,
+    .has_mpu = true,
+    .has_itm = true, /* no ETM? */
+    .num_irq = 44,
+    .nvic_bits = 4 /**/
+};
+
+static const CortexMCapabilities stm32f1cl_core = {
+    .cortexm_model = CORTEX_M3,
+    .has_mpu = true,
+    .has_etm = true,
+    .has_itm = true,
+    .num_irq = 68,
+    .nvic_bits = 4, /**/
+};
+
+static const CortexMCapabilities stm32f152_core = {
+    .cortexm_model = CORTEX_M3,
+    .has_mpu = true,
+    .has_itm = true, /* TODO: check */
+    .has_etm = true,
+    .num_irq = 57, /* TODO: check */
+    .nvic_bits = 4, /**/
+};
+
+static const CortexMCapabilities stm32f2xx_core = {
+    .cortexm_model = CORTEX_M3,
+    .has_mpu = true,
+    .has_itm = true,
+    .nvic_bits = 4, /**/
+};
+
+static const CortexMCapabilities stm32f3xx_core = {
+    .cortexm_model = CORTEX_M4F,
+    .has_mpu = true,
+    .has_itm = true,
+    .nvic_bits = 4, /**/
+};
+
+static const CortexMCapabilities stm32f4xx_core = {
+    .cortexm_model = CORTEX_M4F,
+    .has_mpu = true,
+    .has_itm = true,
+    .nvic_bits = 4, /**/
+};
+
+static const STM32PartInfo stm32_mcus[] = {
+    {
+        .name = TYPE_STM32F051R8,
+        .flash_size_kb = 64,
+        .sram_size_kb = 8,
+        .core = &stm32f0xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F100RB,
+        .flash_size_kb = 128,
+        .sram_size_kb = 8,
+        .core = &stm32f100_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F103RB, /* STM32F103x[8B] */
+        .flash_size_kb = 128,
+        .sram_size_kb = 20,
+        .core = &stm32f1xx_core,
+        .stm32 = &stm32f103x8b, /**/
+    },
+    {
+        .name = TYPE_STM32F107VC,
+        .flash_size_kb = 256,
+        .sram_size_kb = 64,
+        .core = &stm32f1cl_core,
+        .stm32 = &stm32f10_57_xx, /**/
+    },
+    {
+        .name = TYPE_STM32L152RE,
+        .flash_size_kb = 384, /* 384+12 EEPROM */
+        .sram_size_kb = 48,
+        .core = &stm32f152_core,
+        .stm32 = &stm32l15_12_xd, /**/
+    },
+    {
+        .name = TYPE_STM32F205RF,
+        .flash_size_kb = 768,
+        .sram_size_kb = 128, /* No CCM */
+        .core = &stm32f2xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F303VC,
+        .flash_size_kb = 256,
+        .sram_size_kb = 40,
+        .core = &stm32f3xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F334R8,
+        .flash_size_kb = 64,
+        .sram_size_kb = 12,
+        .core = &stm32f3xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F405RG,
+        .flash_size_kb = 1024,
+        .sram_size_kb = 128, /* 64K CCM not counted */
+        .core = &stm32f4xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F407VG,
+        .flash_size_kb = 1024,
+        .sram_size_kb = 128, /* 64K CCM not counted */
+        .core = &stm32f4xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F407ZG,
+        .flash_size_kb = 1024,
+        .sram_size_kb = 128, /* 64K CCM not counted */
+        .core = &stm32f4xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F411RE,
+        .flash_size_kb = 512,
+        .sram_size_kb = 128, /* No CCM */
+        .core = &stm32f4xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = TYPE_STM32F429ZI,
+        .flash_size_kb = 2048,
+        .sram_size_kb = 192, /* 64K CCM not counted */
+        .core = &stm32f4xx_core, /* TODO: Add .stm32 */
+    },
+    {
+        .name = 0 /* End of array. */
+    } /**/
+};
+
+/* ------------------------------------------------------------------------- */
+
+static void stm32_mcus_construct_callback(Object *obj, MachineState *machine)
+{
+    qemu_log_function_name();
+
+    STM32DeviceClass *st_class = STM32_DEVICE_GET_CLASS(obj);
+
+    STM32PartInfo *part_info = st_class->part_info;
+    STM32_MCU_GET_CLASS(obj)->construct(obj, part_info->stm32, part_info->core,
+            part_info->flash_size_kb, part_info->sram_size_kb, machine);
+}
+
+static void stm32_mcus_realize_callback(DeviceState *dev, Error **errp)
+{
+    qemu_log_function_name();
+
+    /* Call the parent realize(). */
+    DeviceClass *parent_class = DEVICE_CLASS(
+            object_class_by_name(TYPE_STM32_MCU));
+    Error *local_err = NULL;
+    parent_class->realize(dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+}
+
+static Property stm32_mcus_properties[] = {
+    /* TODO: add STM32 specific properties */
+    DEFINE_PROP_END_OF_LIST(), /**/
+};
+
+static void stm32_mcus_class_init_callback(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    STM32DeviceClass *st_class = (STM32DeviceClass *) (klass);
+
+    dc->realize = stm32_mcus_realize_callback;
+    dc->props = stm32_mcus_properties;
+
+    st_class->construct = stm32_mcus_construct_callback;
+
+    /*
+     * Copy the 'data' param, pointing to a ParamInfo, to the class
+     * structure, to be retrieved by the constructor.
+     */
+    st_class->part_info = data;
+}
+
+/**
+ * Register all devices described in the table.
+ * Pass the pointer to the table element as .class_data
+ * to the .class_init.
+ */
+static void stm32_mcus_types_init()
+{
+
+    for (int i = 0; stm32_mcus[i].name; ++i) {
+
+        TypeInfo ti = {
+            .name = stm32_mcus[i].name,
+            .parent = TYPE_STM32_MCU,
+            .instance_size = sizeof(STM32DeviceState),
+            .class_init = stm32_mcus_class_init_callback,
+            .class_size = sizeof(STM32DeviceClass),
+            .class_data = (void *) &stm32_mcus[i] };
+        type_register(&ti);
+    }
+}
+
+#if defined(CONFIG_GNU_ARM_ECLIPSE)
+type_init(stm32_mcus_types_init);
+#endif
+
+/* ------------------------------------------------------------------------- */
diff --git a/include/hw/arm/stm32-capabilities.h b/include/hw/arm/stm32-capabilities.h
new file mode 100644
index 0000000..a885c47
--- /dev/null
+++ b/include/hw/arm/stm32-capabilities.h
@@ -0,0 +1,191 @@ 
+/*
+ * STM32 capabilities definitions.
+ *
+ * Copyright (c) 2015 Liviu Ionescu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#ifndef STM32_CAPABILITIES_H_
+#define STM32_CAPABILITIES_H_
+
+#include <stdint.h>
+
+/**
+ * This file defines the members used in the structure used to describe
+ * the capabilities of the STM32 MCUs.
+ *
+ * STM32 MCUs are grouped by families and sub-families.
+ */
+
+/**
+ * The family is the main differentiator for STM32 MCUs.
+ */
+typedef enum {
+    STM32_FAMILY_UNKNOWN,
+    STM32_FAMILY_F0,
+    STM32_FAMILY_F1,
+    STM32_FAMILY_F2,
+    STM32_FAMILY_F3,
+    STM32_FAMILY_F4,
+    STM32_FAMILY_L1,
+} stm32_family_t;
+
+#define STM32_MAX_GPIO  (8)
+
+typedef struct {
+
+    stm32_family_t family;
+
+    /*
+     * Properties common to all families
+     */
+    uint32_t hsi_freq_hz;
+    uint32_t lsi_freq_hz;
+
+    unsigned int eeprom_size_kb;
+
+    /*
+     * Peripherals common to all families.
+     */
+    unsigned int has_rcc :1;
+    unsigned int has_pwr :1;
+
+    /* GPIOs */
+    unsigned int has_gpioa :1;
+    unsigned int has_gpiob :1;
+    unsigned int has_gpioc :1;
+    unsigned int has_gpiod :1;
+    unsigned int has_gpioe :1;
+    unsigned int has_gpiof :1;
+    unsigned int has_gpiog :1;
+    unsigned int has_gpioh :1;
+    /* EXTI */
+    unsigned int has_exti :1;
+    /* DMA */
+    unsigned int has_dma :1;
+    unsigned int has_dma1 :1;
+    unsigned int has_dma2 :1;
+
+    /* Advanced control timers */
+    unsigned int has_ac_tim1 :1;
+    unsigned int has_ac_tim8 :1;
+    /* General-purpose timers */
+    unsigned int has_gp1_tim2 :1;
+    unsigned int has_gp1_tim3 :1;
+    unsigned int has_gp1_tim4 :1;
+    unsigned int has_gp1_tim5 :1;
+    /* General-purpose timers */
+    unsigned int has_gp2_tim9 :1;
+    unsigned int has_gp2_tim12 :1;
+    /* General-purpose timers */
+    unsigned int has_gp3_tim10 :1;
+    unsigned int has_gp3_tim11 :1;
+    unsigned int has_gp3_tim13 :1;
+    unsigned int has_gp3_tim14 :1;
+    /* Basic timers */
+    unsigned int has_bc_tim6 :1;
+    unsigned int has_bc_tim7 :1;
+    /* Watchdogs */
+    unsigned int has_iwdg :1;
+    unsigned int has_wwdg :1;
+
+    /* I2C */
+    unsigned int has_i2c :1;
+    unsigned int has_i2c1 :1;
+    unsigned int has_i2c2 :1;
+
+    /* Universal synchronous/asynchronous */
+    unsigned int has_usart1 :1;
+    unsigned int has_usart2 :1;
+    unsigned int has_usart3 :1;
+    /* Universal asynchronous */
+    unsigned int has_uart4 :1;
+    unsigned int has_uart5 :1;
+
+    /* SPI */
+    unsigned int has_spi1 :1;
+    unsigned int has_spi2 :1;
+    unsigned int has_spi3 :1;
+
+    /* I2S */
+    unsigned int has_i2s1 :1;
+    unsigned int has_i2s2 :1;
+
+    /* Memory */
+    unsigned int has_fsmc :1;
+
+    /* SDIO */
+    unsigned int has_sdio :1;
+
+    /* Ethernet */
+    unsigned int has_eth :1;
+    /* CAN */
+    unsigned int has_bx_can1 :1;
+    unsigned int has_bx_can2 :1;
+    unsigned int has_can1 :1;
+    unsigned int has_can2 :1;
+    /* ADC */
+    unsigned int has_adc :1;
+    unsigned int has_adc1 :1;
+    unsigned int has_adc2 :1;
+    /* DAC */
+    unsigned int has_dac :1;
+    unsigned int has_dac1 :1;
+    unsigned int has_dac2 :1;
+    /* USB */
+    unsigned int has_usb_fs :1;
+    unsigned int has_usb_otg_fs :1;
+
+    /* RTC */
+    unsigned int has_rtc :1;
+
+    /* CRC */
+    unsigned int has_crc :1;
+
+    /* Temperature sensor */
+    unsigned int has_ts :1;
+
+    /* Keep them together */
+    unsigned char num_exti;
+    unsigned char num_dma1;
+    unsigned char num_dma2;
+    unsigned char num_dma;
+
+    /* Number of backup bytes */
+    unsigned int num_bkp;
+
+    /*
+     * Note: the family definitions are mutual exclusive, and could
+     * be packed in a union, but this makes writing the definitions
+     * more complicated and was discarded.
+     * The memory penalty is not significant.
+     */
+    struct {
+        unsigned int is_ld :1; /* is low density */
+        unsigned int is_md :1; /* is medium density */
+        unsigned int is_hd :1; /* is high density */
+        unsigned int is_xd :1; /* is extra density */
+        unsigned int is_cl :1; /* is Connectivity Line */
+        unsigned int is_ldvl :1; /* is low density */
+        unsigned int is_mdvl :1; /* is medium density */
+        unsigned int is_hdvl :1; /* is high density */
+
+    } f1;
+
+    /* TODO: add other families that have sub-families. */
+
+} STM32Capabilities;
+
+#endif /* STM32_CAPABILITIES_H_ */
diff --git a/include/hw/arm/stm32-mcu.h b/include/hw/arm/stm32-mcu.h
new file mode 100644
index 0000000..8ecc76c
--- /dev/null
+++ b/include/hw/arm/stm32-mcu.h
@@ -0,0 +1,89 @@ 
+/*
+ * STM32 Cortex-M devices emulation.
+ *
+ * Copyright (c) 2014 Liviu Ionescu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#ifndef STM32_MCU_H
+#define STM32_MCU_H
+
+#include "hw/boards.h"
+#include "hw/arm/cortexm-mcu.h"
+#include "hw/misc/stm32-rcc.h"
+#include "hw/misc/stm32-flash.h"
+#include "hw/gpio/stm32-gpio.h"
+
+/* ------------------------------------------------------------------------- */
+
+#define TYPE_STM32_MCU "stm32-mcu"
+
+#define STM32_MCU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(STM32MCUClass, (obj), TYPE_STM32_MCU)
+#define STM32_MCU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(STM32MCUClass, (klass), TYPE_STM32_MCU)
+
+typedef struct STM32MCUClass {
+    /*< private >*/
+    CortexMClass parent_class;
+    /*< public >*/
+
+    void (*construct)(Object *obj, const STM32Capabilities* capabilities,
+            const CortexMCapabilities *core_capabilities,
+            const int param_flash_size_kb, const int param_sram_size_kb,
+            MachineState *machine);
+
+} STM32MCUClass;
+
+#define STM32_MCU_STATE(obj) \
+    OBJECT_CHECK(STM32MCUState, (obj), TYPE_STM32_MCU)
+
+typedef struct STM32MCUState {
+    /*< private >*/
+    CortexMState parent_obj;
+    /*< public >*/
+
+    /* Specific STM32 capabilities; Cortex-M capabilities are separate. */
+    const STM32Capabilities *capabilities;
+
+    Object *container;
+
+    DeviceState *rcc;
+    DeviceState *flash;
+    DeviceState *gpio[STM32_MAX_GPIO];
+} STM32MCUState;
+
+/* ------ Public ----------------------------------------------------------- */
+
+/*
+ * Might be deprecated in the future; peripherals are named and can be
+ * obtained by name.
+ */
+
+G_INLINE_FUNC DeviceState *stm32_mcu_get_rcc_dev(DeviceState *dev)
+{
+    return DEVICE((STM32_MCU_STATE(dev)->rcc));
+}
+
+G_INLINE_FUNC DeviceState *stm32_mcu_get_gpio_dev(DeviceState *dev,
+        int port_index)
+{
+    assert(port_index < STM32_MAX_GPIO);
+    return DEVICE((STM32_MCU_STATE(dev)->gpio[port_index]));
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* STM32_MCU_H */
diff --git a/include/hw/arm/stm32-mcus.h b/include/hw/arm/stm32-mcus.h
new file mode 100644
index 0000000..6e7d888
--- /dev/null
+++ b/include/hw/arm/stm32-mcus.h
@@ -0,0 +1,89 @@ 
+/*
+ * STM32 Cortex-M devices emulation.
+ *
+ * Copyright (c) 2014 Liviu Ionescu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/>.
+ */
+
+#ifndef STM32_MCUS_H
+#define STM32_MCUS_H
+
+#include "hw/arm/stm32-mcu.h"
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * For compatibility with some development tools, it is
+ * strongly recommended to use the CMSIS names.
+ */
+#define TYPE_STM32F051R8 "STM32F051R8"
+#define TYPE_STM32F100RB "STM32F100RB"
+#define TYPE_STM32F103RB "STM32F103RB"
+#define TYPE_STM32F107VC "STM32F107VC"
+#define TYPE_STM32L152RE "STM32L152RE"
+#define TYPE_STM32F205RF "STM32F205RF"
+#define TYPE_STM32F303VC "STM32F303VC"
+#define TYPE_STM32F334R8 "STM32F334R8"
+#define TYPE_STM32F405RG "STM32F405RG"
+#define TYPE_STM32F407VG "STM32F407VG"
+#define TYPE_STM32F407ZG "STM32F407ZG"
+#define TYPE_STM32F411RE "STM32F411RE"
+#define TYPE_STM32F429ZI "STM32F429ZI"
+
+/*
+ * Warning, this cast does not check the type!
+ */
+#define STM32_DEVICE_GET_CLASS(obj) \
+    ((STM32DeviceClass *)object_get_class(OBJECT(obj)))
+
+/**
+ * Structure to define the specifics of each MCU. Capabilities are
+ * split between core & stm32; they care processed by parent class
+ * constructors.
+ */
+typedef struct {
+
+    const char *name; /* CMSIS device name */
+
+    const unsigned int flash_size_kb; /* size of main program area, in KB */
+    const unsigned int sram_size_kb; /* size of main RAM area, in KB */
+
+    const CortexMCapabilities *core;
+    const STM32Capabilities *stm32;
+
+} STM32PartInfo;
+
+typedef struct {
+    /*< private >*/
+    STM32MCUClass parent_class;
+    /*< public >*/
+
+    /**
+     * Constructor. Must be called manually after allocation.
+     */
+    void (*construct)(Object *obj, MachineState *machine);
+    STM32PartInfo *part_info;
+} STM32DeviceClass;
+
+typedef struct {
+    /*< private >*/
+    STM32MCUState parent_class;
+    /*< public >*/
+
+} STM32DeviceState;
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* STM32_MCUS_H */