aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/ARMCM4-STM32F407-DISCOVERY/Makefile4
-rw-r--r--docs/reports/STM32F407-168-GCC-FPU.txt164
-rw-r--r--os/hal/platforms/STM32/RTCv1/rtc_lld.c2
-rw-r--r--os/ports/GCC/ARMCMx/chcore_v7m.c109
-rw-r--r--os/ports/GCC/ARMCMx/chcore_v7m.h56
-rw-r--r--os/ports/GCC/ARMCMx/nvic.h69
-rw-r--r--readme.txt1
7 files changed, 368 insertions, 37 deletions
diff --git a/demos/ARMCM4-STM32F407-DISCOVERY/Makefile b/demos/ARMCM4-STM32F407-DISCOVERY/Makefile
index d6c23ea1f..0c614db80 100644
--- a/demos/ARMCM4-STM32F407-DISCOVERY/Makefile
+++ b/demos/ARMCM4-STM32F407-DISCOVERY/Makefile
@@ -5,7 +5,7 @@
# Compiler options here.
ifeq ($(USE_OPT),)
- USE_OPT = -O2 -ggdb -fomit-frame-pointer
+ USE_OPT = -O2 -ggdb -fomit-frame-pointer -mhard-float
endif
# C specific options here (added to USE_OPT).
@@ -120,7 +120,7 @@ INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
# Compiler settings
#
-MCU = cortex-m3
+MCU = cortex-m4
#TRGT = arm-elf-
TRGT = arm-none-eabi-
diff --git a/docs/reports/STM32F407-168-GCC-FPU.txt b/docs/reports/STM32F407-168-GCC-FPU.txt
new file mode 100644
index 000000000..47dc76c84
--- /dev/null
+++ b/docs/reports/STM32F407-168-GCC-FPU.txt
@@ -0,0 +1,164 @@
+***************************************************************************
+Options: -O2 -fomit-frame-pointer -falign-functions=16
+Settings: SYSCLK=168, ACR=0x705 (5 wait states)
+***************************************************************************
+
+*** ChibiOS/RT test suite
+***
+*** Kernel: 2.3.5unstable
+*** Compiled: Dec 11 2011 - 17:14:07
+*** Compiler: GCC 4.6.2
+*** Architecture: ARMv7-ME
+*** Core Variant: Cortex-M4F
+*** Port Info: Advanced kernel mode
+*** Platform: STM32F4 High Performance & DSP
+*** Test Board: ST STM32F4-Discovery
+
+----------------------------------------------------------------------------
+--- Test Case 1.1 (Threads, enqueuing test #1)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 1.2 (Threads, enqueuing test #2)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 1.3 (Threads, priority change)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 1.4 (Threads, delays)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 2.1 (Semaphores, enqueuing)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 2.2 (Semaphores, timeout)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 2.3 (Semaphores, atomic signal-wait)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 2.4 (Binary Semaphores, functionality)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.1 (Mutexes, priority enqueuing test)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.2 (Mutexes, priority inheritance, simple case)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.3 (Mutexes, priority inheritance, complex case)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.4 (Mutexes, priority return)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.5 (Mutexes, status)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.6 (CondVar, signal test)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.7 (CondVar, broadcast test)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 3.8 (CondVar, boost test)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 4.1 (Messages, loop)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 5.1 (Mailboxes, queuing and timeouts)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 6.1 (Events, registration and dispatch)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 6.2 (Events, wait and broadcast)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 6.3 (Events, timeouts)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 7.1 (Heap, allocation and fragmentation test)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 8.1 (Memory Pools, queue/dequeue)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 9.1 (Dynamic APIs, threads creation from heap)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 9.2 (Dynamic APIs, threads creation from memory pool)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 9.3 (Dynamic APIs, registry and references)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 10.1 (Queues, input queues)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 10.2 (Queues, output queues)
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.1 (Benchmark, messages #1)
+--- Score : 559399 msgs/S, 1118798 ctxswc/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.2 (Benchmark, messages #2)
+--- Score : 476758 msgs/S, 953516 ctxswc/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.3 (Benchmark, messages #3)
+--- Score : 476757 msgs/S, 953514 ctxswc/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.4 (Benchmark, context switch)
+--- Score : 1639312 ctxswc/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.5 (Benchmark, threads, full cycle)
+--- Score : 371289 threads/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.6 (Benchmark, threads, create only)
+--- Score : 496514 threads/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.7 (Benchmark, mass reschedule, 5 threads)
+--- Score : 151014 reschedules/S, 906084 ctxswc/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.8 (Benchmark, round robin context switching)
+--- Score : 1018620 ctxswc/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.9 (Benchmark, I/O Queues throughput)
+--- Score : 1766592 bytes/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.10 (Benchmark, virtual timers set/reset)
+--- Score : 1997950 timers/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.11 (Benchmark, semaphores wait/signal)
+--- Score : 2601996 wait+signal/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.12 (Benchmark, mutexes lock/unlock)
+--- Score : 1766592 lock+unlock/S
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+--- Test Case 11.13 (Benchmark, RAM footprint)
+--- System: 648 bytes
+--- Thread: 72 bytes
+--- Timer : 20 bytes
+--- Semaph: 12 bytes
+--- EventS: 4 bytes
+--- EventL: 12 bytes
+--- Mutex : 16 bytes
+--- CondV.: 8 bytes
+--- Queue : 32 bytes
+--- MailB.: 40 bytes
+--- Result: SUCCESS
+----------------------------------------------------------------------------
+
+Final result: SUCCESS
diff --git a/os/hal/platforms/STM32/RTCv1/rtc_lld.c b/os/hal/platforms/STM32/RTCv1/rtc_lld.c
index 931d028f4..1330e106e 100644
--- a/os/hal/platforms/STM32/RTCv1/rtc_lld.c
+++ b/os/hal/platforms/STM32/RTCv1/rtc_lld.c
@@ -215,7 +215,7 @@ void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) {
* @brief Get current time.
*
* @param[in] rtcp pointer to RTC driver structure
- * @param[out] timespec pointer to a @p RTCTime structure
+ * @param[in] timespec pointer to a @p RTCTime structure
*
* @notapi
*/
diff --git a/os/ports/GCC/ARMCMx/chcore_v7m.c b/os/ports/GCC/ARMCMx/chcore_v7m.c
index e8a1ff16e..936823755 100644
--- a/os/ports/GCC/ARMCMx/chcore_v7m.c
+++ b/os/ports/GCC/ARMCMx/chcore_v7m.c
@@ -31,18 +31,36 @@
/**
* @brief Internal context stacking.
*/
+#if CORTEX_USE_FPU || defined(__DOXYGEN__)
+#define PUSH_CONTEXT() { \
+ asm volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" \
+ : : : "memory"); \
+ asm volatile ("vpush {s16-s31}" \
+ : : : "memory"); \
+}
+#else /* !CORTEX_USE_FPU */
#define PUSH_CONTEXT() { \
asm volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" \
: : : "memory"); \
}
+#endif /* !CORTEX_USE_FPU */
/**
* @brief Internal context unstacking.
*/
+#if CORTEX_USE_FPU || defined(__DOXYGEN__)
+#define POP_CONTEXT() { \
+ asm volatile ("vpop {s16-s31}" \
+ : : : "memory"); \
+ asm volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" \
+ : : : "memory"); \
+}
+#else /* !CORTEX_USE_FPU */
#define POP_CONTEXT() { \
asm volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" \
: : : "memory"); \
}
+#endif /* !CORTEX_USE_FPU */
#if !CH_OPTIMIZE_SPEED
void _port_lock(void) {
@@ -80,13 +98,21 @@ CH_IRQ_HANDLER(SysTickVector) {
* @note The PendSV vector is only used in advanced kernel mode.
*/
void SVCallVector(void) {
- register struct extctx *ctxp;
+ uint32_t *psp;
+
+ /* Current PSP value.*/
+ asm volatile ("mrs %0, PSP" : "=r" (psp) : : "memory");
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
- asm volatile ("mrs %0, PSP" : "=r" (ctxp) : : "memory");
- ctxp++;
- asm volatile ("msr PSP, %0" : : "r" (ctxp) : "memory");
+ psp = (uint32_t *)((struct extctx *)psp + 1);
+
+#if CORTEX_USE_FPU
+ /* Restoring the special registers SCB_FPCCR and FPCAR.*/
+ SCB_FPCAR = *psp++;
+ SCB_FPCCR = *psp++;
+#endif
+ asm volatile ("msr PSP, %0" : : "r" (psp) : "memory");
port_unlock_from_isr();
}
#endif /* !CORTEX_SIMPLIFIED_PRIORITY */
@@ -99,29 +125,90 @@ void SVCallVector(void) {
* @note The PendSV vector is only used in compact kernel mode.
*/
void PendSVVector(void) {
- register struct extctx *ctxp;
+ uint32_t *psp;
+
+ /* Current PSP value.*/
+ asm volatile ("mrs %0, PSP" : "=r" (psp) : : "memory");
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
- asm volatile ("mrs %0, PSP" : "=r" (ctxp) : : "memory");
- ctxp++;
- asm volatile ("msr PSP, %0" : : "r" (ctxp) : "memory");
+ psp = (uint32_t *)((struct extctx *)psp + 1);
+
+#if CORTEX_USE_FPU
+ /* Restoring the special registers SCB_FPCCR and FPCAR.*/
+ SCB_FPCAR = *psp++;
+ SCB_FPCCR = *psp++;
+#endif
+ asm volatile ("msr PSP, %0" : : "r" (psp) : "memory");
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
/**
+ * @brief Port-related initialization code.
+ */
+void _port_init(void) {
+ uint32_t reg;
+
+ /* Initialization of the vector table and priority related settings.*/
+ SCB_VTOR = CORTEX_VTOR_INIT;
+ SCB_AIRCR = AIRCR_VECTKEY | AIRCR_PRIGROUP(0);
+
+#if CORTEX_USE_FPU
+ /* CP10 and CP11 set to full access.*/
+ SCB_CPACR |= 0x00F00000;
+
+ /* Enables FPU context save/restore on exception entry/exit (FPCA bit).*/
+ asm volatile ("mrs %0, CONTROL" : "=r" (reg) : : "memory");
+ reg |= 4;
+ asm volatile ("msr CONTROL, %0" : : "r" (reg) : "memory");
+
+ /* FPSCR and FPDSCR initially zero.*/
+ reg = 0;
+ asm volatile ("vmsr FPSCR, %0" : : "r" (reg) : "memory");
+ SCB_FPDSCR = reg;
+
+ /* Initializing the FPU context save in lazy mode.*/
+ SCB_FPCCR = FPCCR_ASPEN | FPCCR_LSPEN;
+#endif
+
+ /* Initialization of the system vectors used by the port.*/
+ NVICSetSystemHandlerPriority(HANDLER_SVCALL,
+ CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SVCALL));
+ NVICSetSystemHandlerPriority(HANDLER_PENDSV,
+ CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_PENDSV));
+ NVICSetSystemHandlerPriority(HANDLER_SYSTICK,
+ CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SYSTICK));
+}
+/**
* @brief Exception exit redirection to _port_switch_from_isr().
*/
void _port_irq_epilogue(void) {
port_lock_from_isr();
if ((SCB_ICSR & ICSR_RETTOBASE)) {
- register struct extctx *ctxp;
+ uint32_t *psp;
+ struct extctx *ctxp;
+
+ /* Current PSP value.*/
+ asm volatile ("mrs %0, PSP" : "=r" (psp) : : "memory");
+
+#if CORTEX_USE_FPU
+ {
+ uint32_t fpccr;
+
+ /* Saving the special registers SCB_FPCCR and FPCAR as extra context.*/
+ *--psp = fpccr = SCB_FPCCR;
+ *--psp = SCB_FPCAR;
+
+ /* Now the FPCCR is modified in order to not restore the FPU status
+ from the artificial return context.*/
+ SCB_FPCCR = fpccr | FPCCR_LSPACT;
+ }
+#endif
/* Adding an artificial exception return context, there is no need to
populate it fully.*/
- asm volatile ("mrs %0, PSP" : "=r" (ctxp) : : "memory");
- ctxp--;
+ ctxp = ((struct extctx *)psp) - 1;
asm volatile ("msr PSP, %0" : : "r" (ctxp) : "memory");
ctxp->pc = _port_switch_from_isr;
ctxp->xpsr = (regarm_t)0x01000000;
diff --git a/os/ports/GCC/ARMCMx/chcore_v7m.h b/os/ports/GCC/ARMCMx/chcore_v7m.h
index 14fca144c..8dd42f909 100644
--- a/os/ports/GCC/ARMCMx/chcore_v7m.h
+++ b/os/ports/GCC/ARMCMx/chcore_v7m.h
@@ -47,7 +47,7 @@
* @details Activating this option will make the Kernel work in compact mode.
*/
#if !defined(CORTEX_USE_FPU)
-#define CORTEX_USE_FPU FALSE/*CORTEX_HAS_FPU*/
+#define CORTEX_USE_FPU CORTEX_HAS_FPU
#elif CORTEX_USE_FPU && !CORTEX_HAS_FPU
/* This setting requires an FPU presence check in case it is externally
redefined.*/
@@ -129,8 +129,12 @@
#elif (CORTEX_MODEL == CORTEX_M4)
#define CH_ARCHITECTURE_ARM_v7ME
#define CH_ARCHITECTURE_NAME "ARMv7-ME"
+#if CORTEX_USE_FPU
+#define CH_CORE_VARIANT_NAME "Cortex-M4F"
+#else
#define CH_CORE_VARIANT_NAME "Cortex-M4"
#endif
+#endif
/**
* @brief Port-specific information string.
@@ -162,9 +166,47 @@ struct extctx {
regarm_t lr_thd;
regarm_t pc;
regarm_t xpsr;
+#if CORTEX_USE_FPU || defined(__DOXYGEN__)
+ regarm_t s0;
+ regarm_t s1;
+ regarm_t s2;
+ regarm_t s3;
+ regarm_t s4;
+ regarm_t s5;
+ regarm_t s6;
+ regarm_t s7;
+ regarm_t s8;
+ regarm_t s9;
+ regarm_t s10;
+ regarm_t s11;
+ regarm_t s12;
+ regarm_t s13;
+ regarm_t s14;
+ regarm_t s15;
+ regarm_t fpscr;
+ regarm_t reserved;
+#endif /* CORTEX_USE_FPU */
};
struct intctx {
+#if CORTEX_USE_FPU || defined(__DOXYGEN__)
+ regarm_t s16;
+ regarm_t s17;
+ regarm_t s18;
+ regarm_t s19;
+ regarm_t s20;
+ regarm_t s21;
+ regarm_t s22;
+ regarm_t s23;
+ regarm_t s24;
+ regarm_t s25;
+ regarm_t s26;
+ regarm_t s27;
+ regarm_t s28;
+ regarm_t s29;
+ regarm_t s30;
+ regarm_t s31;
+#endif /* CORTEX_USE_FPU */
regarm_t r4;
regarm_t r5;
regarm_t r6;
@@ -208,16 +250,7 @@ struct intctx {
/**
* @brief Port-related initialization code.
*/
-#define port_init() { \
- SCB_VTOR = CORTEX_VTOR_INIT; \
- SCB_AIRCR = AIRCR_VECTKEY | AIRCR_PRIGROUP(0); \
- NVICSetSystemHandlerPriority(HANDLER_SVCALL, \
- CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SVCALL)); \
- NVICSetSystemHandlerPriority(HANDLER_PENDSV, \
- CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_PENDSV)); \
- NVICSetSystemHandlerPriority(HANDLER_SYSTICK, \
- CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SYSTICK)); \
-}
+#define port_init() _port_init()
/**
* @brief Kernel-lock action.
@@ -357,6 +390,7 @@ struct intctx {
extern "C" {
#endif
void port_halt(void);
+ void _port_init(void);
void _port_switch(Thread *ntp, Thread *otp);
void _port_irq_epilogue(void);
void _port_switch_from_isr(void);
diff --git a/os/ports/GCC/ARMCMx/nvic.h b/os/ports/GCC/ARMCMx/nvic.h
index 02f010c4a..b7cc249b5 100644
--- a/os/ports/GCC/ARMCMx/nvic.h
+++ b/os/ports/GCC/ARMCMx/nvic.h
@@ -54,11 +54,6 @@ typedef volatile uint32_t IOREG32; /**< 32 bits I/O register type. */
#define NVIC_ITCR (*((IOREG32 *)0xE000E004))
/**
- * @brief NVIC STIR register.
- */
-#define NVIC_STIR (*((IOREG32 *)0xE000EF00))
-
-/**
* @brief Structure representing the SYSTICK I/O space.
*/
typedef struct {
@@ -66,12 +61,12 @@ typedef struct {
IOREG32 RVR;
IOREG32 CVR;
IOREG32 CBVR;
-} CM3_ST;
+} CMx_ST;
/**
* @brief SYSTICK peripheral base address.
*/
-#define STBase ((CM3_ST *)0xE000E010)
+#define STBase ((CMx_ST *)0xE000E010)
#define ST_CSR (STBase->CSR)
#define ST_RVR (STBase->RVR)
#define ST_CVR (STBase->CVR)
@@ -111,18 +106,21 @@ typedef struct {
IOREG32 IABR[8];
IOREG32 unused5[56];
IOREG32 IPR[60];
-} CM3_NVIC;
+ IOREG32 unused6[644];
+ IOREG32 STIR;
+} CMx_NVIC;
/**
* @brief NVIC peripheral base address.
*/
-#define NVICBase ((CM3_NVIC *)0xE000E100)
+#define NVICBase ((CMx_NVIC *)0xE000E100)
#define NVIC_ISER(n) (NVICBase->ISER[n])
#define NVIC_ICER(n) (NVICBase->ICER[n])
#define NVIC_ISPR(n) (NVICBase->ISPR[n])
#define NVIC_ICPR(n) (NVICBase->ICPR[n])
#define NVIC_IABR(n) (NVICBase->IABR[n])
#define NVIC_IPR(n) (NVICBase->IPR[n])
+#define NVIC_STIR (NVICBase->STIR)
/**
* @brief Structure representing the System Control Block I/O space.
@@ -142,12 +140,19 @@ typedef struct {
IOREG32 MMFAR;
IOREG32 BFAR;
IOREG32 AFSR;
-} CM3_SCB;
+ IOREG32 PFR[2];
+ IOREG32 DFR;
+ IOREG32 ADR;
+ IOREG32 MMFR[4];
+ IOREG32 SAR[5];
+ IOREG32 unused1[5];
+ IOREG32 CPACR;
+} CMx_SCB;
/**
* @brief SCB peripheral base address.
*/
-#define SCBBase ((CM3_SCB *)0xE000ED00)
+#define SCBBase ((CMx_SCB *)0xE000ED00)
#define SCB_CPUID (SCBBase->CPUID)
#define SCB_ICSR (SCBBase->ICSR)
#define SCB_VTOR (SCBBase->VTOR)
@@ -162,6 +167,12 @@ typedef struct {
#define SCB_MMFAR (SCBBase->MMFAR)
#define SCB_BFAR (SCBBase->BFAR)
#define SCB_AFSR (SCBBase->AFSR)
+#define SCB_PFR(n) (SCBBase->PFR[n])
+#define SCB_DFR (SCBBase->DFR)
+#define SCB_ADR (SCBBase->ADR)
+#define SCB_MMFR(n) (SCBBase->MMFR[n])
+#define SCB_SAR(n) (SCBBase->SAR[n])
+#define SCB_CPACR (SCBBase->CPACR)
#define ICSR_VECTACTIVE_MASK (0x1FF << 0)
#define ICSR_RETTOBASE (0x1 << 11)
@@ -172,12 +183,46 @@ typedef struct {
#define ICSR_PENDSTSET (0x1 << 26)
#define ICSR_PENDSVCLR (0x1 << 27)
#define ICSR_PENDSVSET (0x1 << 28)
-#define ICSR_NMIPENDSET (0x1 << 31)
+#define ICSR_NMIPENDSET (0x1U << 31)
#define AIRCR_VECTKEY 0x05FA0000
#define AIRCR_PRIGROUP_MASK (0x7 << 8)
#define AIRCR_PRIGROUP(n) ((n) << 8)
+typedef struct {
+ IOREG32 unused1[1];
+ IOREG32 FPCCR;
+ IOREG32 FPCAR;
+ IOREG32 FPDSCR;
+ IOREG32 MVFR0;
+ IOREG32 MVFR1;
+} CMx_FPU;
+
+/**
+ * @brief FPU peripheral base address.
+ */
+#define FPUBase ((CMx_FPU *)0xE000EF30L)
+#define SCB_FPCCR (FPUBase->FPCCR)
+#define SCB_FPCAR (FPUBase->FPCAR)
+#define SCB_FPDSCR (FPUBase->FPDSCR)
+#define SCB_MVFR0 (FPUBase->MVFR0)
+#define SCB_MVFR1 (FPUBase->MVFR1)
+
+#define FPCCR_ASPEN (0x1U << 31)
+#define FPCCR_LSPEN (0x1U << 30)
+#define FPCCR_MONRDY (0x1U << 8)
+#define FPCCR_BFRDY (0x1U << 6)
+#define FPCCR_MMRDY (0x1U << 5)
+#define FPCCR_HFRDY (0x1U << 4)
+#define FPCCR_THREAD (0x1U << 3)
+#define FPCCR_USER (0x1U << 1)
+#define FPCCR_LSPACT (0x1U << 0)
+
+#define FPDSCR_AHP (0x1U << 26)
+#define FPDSCR_DN (0x1U << 25)
+#define FPDSCR_FZ (0x1U << 24)
+#define FPDSCR_RMODE(n) ((n) << 22)
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/readme.txt b/readme.txt
index d53e7fb73..1cb86d244 100644
--- a/readme.txt
+++ b/readme.txt
@@ -80,6 +80,7 @@
structures and stacks in the CCM RAM instead normal RAM. It is done using
a special .ld file that can be customized to decide how to allocate data
in the various RAM sections.
+- NEW: Added support for the Cortex-M4 FPU (default when the FPU is present).
- NEW: Improved I2C driver model and STM32 implementation by Barthess.
*** 2.3.4 ***