stm32f429i-disc1: Enable hardware FPU

 * Add Cortex-M4 toolchains with floating point hardware instructions.
 * Update stm32f429i-disc1 to use hardware fpu toolchain by default.
 * Add code to enable FPU in pw_dumb_io.

Verified tests that use floating point operations continue to pass.

Change-Id: I76bc7eeaf457eca1abacbc60992648d63dc85bf2
diff --git a/pw_dumb_io_baremetal_stm32f429/BUILD b/pw_dumb_io_baremetal_stm32f429/BUILD
new file mode 100644
index 0000000..2d9f88b
--- /dev/null
+++ b/pw_dumb_io_baremetal_stm32f429/BUILD
@@ -0,0 +1,25 @@
+# Copyright 2019 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache License 2.0
+
+filegroup(
+    name = "pw_dumb_io_baremetal_stm32f429",
+    srcs = [
+        "core_init.c",
+        "dumb_io_baremetal.cc",
+    ],
+)
diff --git a/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc b/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc
index 43f5c42..1c6b288 100644
--- a/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc
+++ b/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc
@@ -161,6 +161,19 @@
   usart1.baud_rate = CalcBaudRegister(kSystemCoreClock, /*target_baud=*/115200);
 
   usart1.config1 = kEnableUsart | kReceiveEnable | kTransmitEnable;
+
+// TODO(pwbug/17): Replace when Pigweed config system is added.
+#if defined(PW_ARMV7M_ENABLE_FPU) && PW_ARMV7M_ENABLE_FPU == 1
+  // Enable FPU if built using hardware FPU instructions.
+  // CPCAR mask that enables FPU. (ARMv7-M Section B3.2.20)
+  constexpr uint32_t kFpuEnableMask = (0xFu << 20);
+
+  // Memory mapped register to enable FPU. (ARMv7-M Section B3.2.2, Table B3-4)
+  volatile uint32_t& arm_v7m_cpacr =
+      *reinterpret_cast<volatile uint32_t*>(0xE000ED88u);
+
+  arm_v7m_cpacr |= kFpuEnableMask;
+#endif  // defined(PW_ARMV7M_ENABLE_FPU) && PW_ARMV7M_ENABLE_FPU == 1
 }
 
 namespace pw::dumb_io {
diff --git a/pw_toolchain/BUILD.gn b/pw_toolchain/BUILD.gn
index f723c13..f7f9962 100644
--- a/pw_toolchain/BUILD.gn
+++ b/pw_toolchain/BUILD.gn
@@ -74,10 +74,20 @@
 generate_toolchains("cortex_m4") {
   toolchain_template = "arm_gcc_toolchain"
 
+  software_fpu_cflags = [ "-mfloat-abi=soft" ]
+
+  hardware_fpu_cflags = [
+    # When hardware FPU is enabled, PW_ARMV7M_ENABLE_FPU is set to 1.
+    # TODO(pwbug/17): Replace when there's a more sophisticated configuration
+    # system.
+    "-DPW_ARMV7M_ENABLE_FPU=1",
+    "-mfloat-abi=hard",
+    "-mfpu=fpv4-sp-d16",
+  ]
+
   common_toolchain_cflags = [
     "-mabi=aapcs",
     "-mcpu=cortex-m4",
-    "-mfloat-abi=soft",
     "-mthumb",
     "-specs=nano.specs",
     "-specs=nosys.specs",
@@ -89,21 +99,48 @@
   ]
 
   toolchains = [
+    # Cortex-M4 toolchains that use software-emulated floating point.
     {
       toolchain_name = "arm_gcc_cortex_m4_og"
       additional_cflags = [ "-Og" ]
+      additional_cflags += software_fpu_cflags
     },
     {
       toolchain_name = "arm_gcc_cortex_m4_o1"
       additional_cflags = [ "-O1" ]
+      additional_cflags += software_fpu_cflags
     },
     {
       toolchain_name = "arm_gcc_cortex_m4_o2"
       additional_cflags = [ "-O2" ]
+      additional_cflags += software_fpu_cflags
     },
     {
       toolchain_name = "arm_gcc_cortex_m4_os"
       additional_cflags = [ "-Os" ]
+      additional_cflags += software_fpu_cflags
+    },
+
+    # Cortex-M4 toolchains that use hardware FPU instructions.
+    {
+      toolchain_name = "arm_gcc_cortex_m4f_og"
+      additional_cflags = [ "-Og" ]
+      additional_cflags += hardware_fpu_cflags
+    },
+    {
+      toolchain_name = "arm_gcc_cortex_m4f_o1"
+      additional_cflags = [ "-O1" ]
+      additional_cflags += hardware_fpu_cflags
+    },
+    {
+      toolchain_name = "arm_gcc_cortex_m4f_o2"
+      additional_cflags = [ "-O2" ]
+      additional_cflags += hardware_fpu_cflags
+    },
+    {
+      toolchain_name = "arm_gcc_cortex_m4f_os"
+      additional_cflags = [ "-Os" ]
+      additional_cflags += hardware_fpu_cflags
     },
   ]
 }
diff --git a/targets/stm32f429i-disc1/target_config.gni b/targets/stm32f429i-disc1/target_config.gni
index b10a89a..ff3d7c6 100644
--- a/targets/stm32f429i-disc1/target_config.gni
+++ b/targets/stm32f429i-disc1/target_config.gni
@@ -23,7 +23,7 @@
 
 declare_args() {
   # Specifies the toolchain to use for this build.
-  pw_target_toolchain = "$dir_pw_toolchain:arm_gcc_cortex_m4_og"
+  pw_target_toolchain = "$dir_pw_toolchain:arm_gcc_cortex_m4f_og"
 }
 
 # Executable wrapper that includes some baremetal startup code.