[PATCH] STM32F100: add support for external memory via FSMC

2023-06-20 Thread Lucas Villa Real
Add support for FSMC on high-density STM32F100 devices and enable
mapping of additional memory via the `-m SIZE` command-line option.
FSMC Bank1 can address up to 4x64MB of PSRAM memory at 0x6000.

RCC is needed to enable peripheral clock for FSMC; this commit
implements support for RCC through the MMIO interface.

Last, high-density devices support up to 32KB of static SRAM, so
adjust SRAM_SIZE accordingly.

Signed-off-by: Lucas C. Villa Real 
---
 docs/system/arm/stm32.rst|  12 ++-
 hw/arm/Kconfig   |   1 +
 hw/arm/stm32f100_soc.c   | 102 +++-
 hw/arm/stm32f1_generic.c |  12 +++
 hw/misc/Kconfig  |   3 +
 hw/misc/meson.build  |   1 +
 hw/misc/stm32f1xx_fsmc.c | 155 +++
 include/hw/arm/stm32f100_soc.h   |  24 -
 include/hw/misc/stm32f1xx_fsmc.h |  62 +
 9 files changed, 368 insertions(+), 4 deletions(-)
 create mode 100644 hw/misc/stm32f1xx_fsmc.c
 create mode 100644 include/hw/misc/stm32f1xx_fsmc.h

diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst
index d0a3b1a7eb..40de58ed04 100644
--- a/docs/system/arm/stm32.rst
+++ b/docs/system/arm/stm32.rst
@@ -40,6 +40,8 @@ Supported devices
  * SPI controller
  * System configuration (SYSCFG)
  * Timer controller (TIMER)
+ * Reset and Clock Controller (RCC)
+ * Flexible static memory controller (FSMC)
 
 Missing devices
 ---
@@ -57,7 +59,6 @@ Missing devices
  * Power supply configuration (PWR)
  * Random Number Generator (RNG)
  * Real-Time Clock (RTC) controller
- * Reset and Clock Controller (RCC)
  * Secure Digital Input/Output (SDIO) interface
  * USB OTG
  * Watchdog controller (IWDG, WWDG)
@@ -78,4 +79,11 @@ to select the device density line.  The following values are 
supported:
 
 .. code-block:: bash
 
-  $ qemu-system-arm -M stm32f1-generic -global stm32f100-soc.density=medium ...
\ No newline at end of file
+  $ qemu-system-arm -M stm32f1-generic -global stm32f100-soc.density=medium ...
+
+High-density devices can also enable up to 256 MB of external memory using
+the `-m SIZE` option. The memory is mapped at address 0x6000. Example:
+ 
+.. code-block:: bash
+
+  $ qemu-system-arm -M stm32f1-generic -m 64M ...
\ No newline at end of file
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 822441945c..dd48068108 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -433,6 +433,7 @@ config RASPI
 config STM32F100_SOC
 bool
 select ARM_V7M
+select STM32F1XX_FSMC
 select STM32F2XX_USART
 select STM32F2XX_SPI
 
diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c
index c157ffd644..a2b863d309 100644
--- a/hw/arm/stm32f100_soc.c
+++ b/hw/arm/stm32f100_soc.c
@@ -26,6 +26,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
+#include "qemu/log.h"
 #include "hw/arm/boot.h"
 #include "exec/address-spaces.h"
 #include "hw/arm/stm32f100_soc.h"
@@ -40,9 +41,85 @@ static const uint32_t usart_addr[STM_NUM_USARTS] = { 
0x40013800, 0x40004400,
 0x40004800 };
 static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800,
 0x40003C00 };
+static const uint32_t fsmc_addr = 0xA000;
 
 static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39};
 static const int spi_irq[STM_NUM_SPIS] = {35, 36, 51};
+static const int fsmc_irq = 48;
+
+static uint64_t stm32f100_rcc_read(void *h, hwaddr offset, unsigned size)
+{
+STM32F100State *s = (STM32F100State *) h;
+switch (offset) {
+case 0x00:
+return s->rcc.cr;
+case 0x04:
+return s->rcc.cfgr;
+case 0x08:
+return s->rcc.cir;
+case 0x0C:
+return s->rcc.apb2rstr;
+case 0x10:
+return s->rcc.apb1rstr;
+case 0x14:
+return s->rcc.ahbenr;
+case 0x18:
+return s->rcc.apb2enr;
+case 0x1C:
+return s->rcc.apb1enr;
+case 0x20:
+return s->rcc.bdcr;
+case 0x24:
+return s->rcc.csr;
+case 0x2C:
+return s->rcc.cfgr2;
+default:
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
+}
+return 0;
+}
+
+static void stm32f100_rcc_write(void *h, hwaddr offset, uint64_t value64,
+unsigned size)
+{
+STM32F100State *s = (STM32F100State *) h;
+uint32_t value = value64 & 0x;
+
+switch (offset) {
+case 0x00:
+s->rcc.cr = value;
+case 0x04:
+s->rcc.cfgr = value;
+case 0x08:
+s->rcc.cir = value;
+case 0x0C:
+s->rcc.apb2rstr = value;
+case 0x10:
+s->rcc.apb1rstr = value;
+case 0x14:
+s->rcc.ahbenr = value;
+case 0x18:
+s->rcc.apb2enr = value;
+case 0x1C:
+s->rcc.apb1enr = value;
+case 0x20:
+s->rcc.bdcr = value;
+case 0x24:
+s->rcc.csr = value;
+case 0x2C:
+s->rcc.cfgr2 = value;
+default:
+

[PATCH] STM32F100: add support for external memory via FSMC

2023-06-20 Thread Lucas Villa Real
Add support for FSMC on high-density STM32F100 devices and enable
mapping of additional memory via the `-m SIZE` command-line option.
FSMC Bank1 can address up to 4x64MB of PSRAM memory at 0x6000.

RCC is needed to enable peripheral clock for FSMC; this commit
implements support for RCC through the MMIO interface.

Last, high-density devices support up to 32KB of static SRAM, so
adjust SRAM_SIZE accordingly.

Signed-off-by: Lucas C. Villa Real 
---
 docs/system/arm/stm32.rst|  12 ++-
 hw/arm/Kconfig   |   1 +
 hw/arm/stm32f100_soc.c   | 102 +++-
 hw/arm/stm32f1_generic.c |  12 +++
 hw/misc/Kconfig  |   3 +
 hw/misc/meson.build  |   1 +
 hw/misc/stm32f1xx_fsmc.c | 155 +++
 include/hw/arm/stm32f100_soc.h   |  24 -
 include/hw/misc/stm32f1xx_fsmc.h |  62 +
 9 files changed, 368 insertions(+), 4 deletions(-)
 create mode 100644 hw/misc/stm32f1xx_fsmc.c
 create mode 100644 include/hw/misc/stm32f1xx_fsmc.h

diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst
index d0a3b1a7eb..40de58ed04 100644
--- a/docs/system/arm/stm32.rst
+++ b/docs/system/arm/stm32.rst
@@ -40,6 +40,8 @@ Supported devices
  * SPI controller
  * System configuration (SYSCFG)
  * Timer controller (TIMER)
+ * Reset and Clock Controller (RCC)
+ * Flexible static memory controller (FSMC)
 
 Missing devices
 ---
@@ -57,7 +59,6 @@ Missing devices
  * Power supply configuration (PWR)
  * Random Number Generator (RNG)
  * Real-Time Clock (RTC) controller
- * Reset and Clock Controller (RCC)
  * Secure Digital Input/Output (SDIO) interface
  * USB OTG
  * Watchdog controller (IWDG, WWDG)
@@ -78,4 +79,11 @@ to select the device density line.  The following values are 
supported:
 
 .. code-block:: bash
 
-  $ qemu-system-arm -M stm32f1-generic -global stm32f100-soc.density=medium ...
\ No newline at end of file
+  $ qemu-system-arm -M stm32f1-generic -global stm32f100-soc.density=medium ...
+
+High-density devices can also enable up to 256 MB of external memory using
+the `-m SIZE` option. The memory is mapped at address 0x6000. Example:
+ 
+.. code-block:: bash
+
+  $ qemu-system-arm -M stm32f1-generic -m 64M ...
\ No newline at end of file
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 822441945c..dd48068108 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -433,6 +433,7 @@ config RASPI
 config STM32F100_SOC
 bool
 select ARM_V7M
+select STM32F1XX_FSMC
 select STM32F2XX_USART
 select STM32F2XX_SPI
 
diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c
index c157ffd644..a2b863d309 100644
--- a/hw/arm/stm32f100_soc.c
+++ b/hw/arm/stm32f100_soc.c
@@ -26,6 +26,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
+#include "qemu/log.h"
 #include "hw/arm/boot.h"
 #include "exec/address-spaces.h"
 #include "hw/arm/stm32f100_soc.h"
@@ -40,9 +41,85 @@ static const uint32_t usart_addr[STM_NUM_USARTS] = { 
0x40013800, 0x40004400,
 0x40004800 };
 static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800,
 0x40003C00 };
+static const uint32_t fsmc_addr = 0xA000;
 
 static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39};
 static const int spi_irq[STM_NUM_SPIS] = {35, 36, 51};
+static const int fsmc_irq = 48;
+
+static uint64_t stm32f100_rcc_read(void *h, hwaddr offset, unsigned size)
+{
+STM32F100State *s = (STM32F100State *) h;
+switch (offset) {
+case 0x00:
+return s->rcc.cr;
+case 0x04:
+return s->rcc.cfgr;
+case 0x08:
+return s->rcc.cir;
+case 0x0C:
+return s->rcc.apb2rstr;
+case 0x10:
+return s->rcc.apb1rstr;
+case 0x14:
+return s->rcc.ahbenr;
+case 0x18:
+return s->rcc.apb2enr;
+case 0x1C:
+return s->rcc.apb1enr;
+case 0x20:
+return s->rcc.bdcr;
+case 0x24:
+return s->rcc.csr;
+case 0x2C:
+return s->rcc.cfgr2;
+default:
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
+}
+return 0;
+}
+
+static void stm32f100_rcc_write(void *h, hwaddr offset, uint64_t value64,
+unsigned size)
+{
+STM32F100State *s = (STM32F100State *) h;
+uint32_t value = value64 & 0x;
+
+switch (offset) {
+case 0x00:
+s->rcc.cr = value;
+case 0x04:
+s->rcc.cfgr = value;
+case 0x08:
+s->rcc.cir = value;
+case 0x0C:
+s->rcc.apb2rstr = value;
+case 0x10:
+s->rcc.apb1rstr = value;
+case 0x14:
+s->rcc.ahbenr = value;
+case 0x18:
+s->rcc.apb2enr = value;
+case 0x1C:
+s->rcc.apb1enr = value;
+case 0x20:
+s->rcc.bdcr = value;
+case 0x24:
+s->rcc.csr = value;
+case 0x2C:
+s->rcc.cfgr2 = value;
+default:
+

[PATCH] STM32F100: support different density lines

2023-06-19 Thread Lucas Villa Real
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 
---
 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", >armv7m, TYPE_ARMV7M);
 
+/*
+ * All 

[PATCH] stm32vldiscovery: allow overriding of RAM size

2023-04-03 Thread Lucas Villa Real
stm32vldiscovery comes with 8KB of SRAM, which may be too low when
running some workloads on QEMU. The command line argument "-m mem_size"
is not recognized by the current implementation, though, so one cannot
easily override the default memory size.

This patch fixes that by adding a memory subregion according to the
value provided on that command line argument. If absent, the default
value of 8KB still applies.

Signed-off-by: Lucas Villa Real 
---
 hw/arm/stm32vldiscovery.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c
index 67675e952f..7ca3ba029e 100644
--- a/hw/arm/stm32vldiscovery.c
+++ b/hw/arm/stm32vldiscovery.c
@@ -29,6 +29,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/qdev-clock.h"
 #include "qemu/error-report.h"
+#include "exec/address-spaces.h"
 #include "hw/arm/stm32f100_soc.h"
 #include "hw/arm/boot.h"
 
@@ -42,6 +43,9 @@ static void stm32vldiscovery_init(MachineState *machine)
 DeviceState *dev;
 Clock *sysclk;
 
+/* Allow overriding the emulated board's RAM size */
+memory_region_add_subregion(get_system_memory(), SRAM_BASE_ADDRESS, 
machine->ram);
+
 /* This clock doesn't need migration because it is fixed-frequency */
 sysclk = clock_new(OBJECT(machine), "SYSCLK");
 clock_set_hz(sysclk, SYSCLK_FRQ);
@@ -60,6 +64,8 @@ static void stm32vldiscovery_machine_init(MachineClass *mc)
 {
 mc->desc = "ST STM32VLDISCOVERY (Cortex-M3)";
 mc->init = stm32vldiscovery_init;
+mc->default_ram_id = "stm32vldiscovery.ram";
+mc->default_ram_size = SRAM_SIZE;
 }
 
 DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
-- 
2.37.1 (Apple Git-137.1)