From 0df3f9d0c024b3aeb508deed7c2a84657230388d Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Sat, 8 Jun 2019 18:25:25 +0200
Subject: [PATCH] feat: Add dual-core example

This dual-core example works by creating two separate elfs and
flashing them to different offsets.

Co-authored-by: schneider <schneider@blinkenlichts.net>
Signed-off-by: Rahix <rahix@rahix.de>
---
 README.md                                     |   1 +
 hw-tests/dual-core/Heart.h                    |   1 +
 hw-tests/dual-core/core1.c                    |  19 +++
 hw-tests/dual-core/flash.gdb                  |  13 ++
 hw-tests/dual-core/main.c                     |  60 +++++++
 hw-tests/dual-core/meson.build                |  19 +++
 hw-tests/meson.build                          |   1 +
 .../MAX32665/Source/GCC/max32665_core0.ld     | 147 ++++++++++++++++++
 .../MAX32665/Source/GCC/max32665_core1.ld     | 147 ++++++++++++++++++
 .../MAX32665/Source/system_max32665_core1.c   | 147 ++++++++++++++++++
 .../CMSIS/Device/Maxim/MAX32665/meson.build   |  52 +++++++
 11 files changed, 607 insertions(+)
 create mode 120000 hw-tests/dual-core/Heart.h
 create mode 100644 hw-tests/dual-core/core1.c
 create mode 100644 hw-tests/dual-core/flash.gdb
 create mode 100644 hw-tests/dual-core/main.c
 create mode 100644 hw-tests/dual-core/meson.build
 create mode 100644 lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core0.ld
 create mode 100644 lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core1.ld
 create mode 100644 lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/system_max32665_core1.c

diff --git a/README.md b/README.md
index ea26519e1..e392db6e1 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,7 @@ Initialize the build-system by running `meson --cross-file card10-cross.ini buil
   - `hw-tests/hello-world/hello-world.elf`
   - `hw-tests/imutest/imutest.elf`
   - `hw-tests/ips/ips.elf`
+  - `hw-tests/dual-core/dual-core{0,1}.elf`
 
 ## Flashing
 Run `arm-none-eabi-gdb` in the applications folder. It should connect to OpenOCD and say something like:
diff --git a/hw-tests/dual-core/Heart.h b/hw-tests/dual-core/Heart.h
new file mode 120000
index 000000000..1276f163b
--- /dev/null
+++ b/hw-tests/dual-core/Heart.h
@@ -0,0 +1 @@
+../hello-world/Heart.h
\ No newline at end of file
diff --git a/hw-tests/dual-core/core1.c b/hw-tests/dual-core/core1.c
new file mode 100644
index 000000000..605bf0e9a
--- /dev/null
+++ b/hw-tests/dual-core/core1.c
@@ -0,0 +1,19 @@
+#include "board.h"
+#include "gpio.h"
+#include "mxc_delay.h"
+
+static const gpio_cfg_t motor_pin = {PORT_0, PIN_8, GPIO_FUNC_OUT, GPIO_PAD_NONE};
+
+int main(void)
+{
+	for (int i = 0; 1; i++) {
+		printf("Hello from core 1! %d\n", i);
+
+#if 0
+		GPIO_OutSet(&motor_pin);
+		mxc_delay(30000);
+		GPIO_OutClr(&motor_pin);
+#endif
+		mxc_delay(970000);
+	}
+}
diff --git a/hw-tests/dual-core/flash.gdb b/hw-tests/dual-core/flash.gdb
new file mode 100644
index 000000000..ea197bee2
--- /dev/null
+++ b/hw-tests/dual-core/flash.gdb
@@ -0,0 +1,13 @@
+source ../../.gdbinit
+
+set confirm off
+
+echo Loading core1 image ...
+file ../../build/hw-tests/dual-core/dual-core1.elf
+load
+echo Loading core0 image ...
+file ../../build/hw-tests/dual-core/dual-core0.elf
+load
+
+reset
+quit
diff --git a/hw-tests/dual-core/main.c b/hw-tests/dual-core/main.c
new file mode 100644
index 000000000..8a8de068f
--- /dev/null
+++ b/hw-tests/dual-core/main.c
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * License: TBD
+ ******************************************************************************/
+
+/***** Includes *****/
+#include "pmic.h"
+#include "leds.h"
+#include "card10.h"
+
+#include "GUI_Paint.h"
+
+#include "tmr_utils.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <Heart.h>
+
+void Core1_Start(void) {
+    //MXC_GCR->gp0 = (uint32_t)(&__isr_vector_core1);
+    MXC_GCR->gp0 = 0x10040000;
+    MXC_GCR->perckcn1 &= ~MXC_F_GCR_PERCKCN1_CPU1;
+}
+
+void Core1_Stop(void) {
+    MXC_GCR->perckcn1 |= MXC_F_GCR_PERCKCN1_CPU1;
+}
+
+int main(void)
+{
+    card10_init();
+    card10_diag();
+
+    Paint_DrawImage(Heart, 0, 0, 160, 80);
+    LCD_Update();
+
+    for(int i=0; i<11; i++) {
+        leds_set_dim(i, 1);
+    }
+
+    int h = 0;
+
+    // Release core1
+    Core1_Start();
+
+    while (1) {
+        #define NUM     15
+        for(int i=0; i<NUM; i++) {
+            if(i < 12) {
+                leds_set_hsv(i, (h + 360/NUM * i) % 360, 1., 1./8);
+            } else {
+                leds_set_hsv(i, (h + 360/NUM * i) % 360, 1., 1.);
+            }
+        }
+
+        leds_update();
+        TMR_Delay(MXC_TMR0, MSEC(10), 0);
+        h++;
+    }
+}
diff --git a/hw-tests/dual-core/meson.build b/hw-tests/dual-core/meson.build
new file mode 100644
index 000000000..2689d8f4e
--- /dev/null
+++ b/hw-tests/dual-core/meson.build
@@ -0,0 +1,19 @@
+name = 'dual-core0'
+executable(
+  name + '.elf',
+  'main.c',
+  dependencies: [libcard10, max32665_startup_core0],
+  link_args: [
+    '-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
+  ],
+)
+
+name = 'dual-core1'
+executable(
+  name + '.elf',
+  'core1.c',
+  dependencies: [periphdriver, board_card10, max32665_startup_core1],
+  link_args: [
+    '-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
+  ],
+)
diff --git a/hw-tests/meson.build b/hw-tests/meson.build
index 537bbcfde..757dccd1a 100644
--- a/hw-tests/meson.build
+++ b/hw-tests/meson.build
@@ -1,5 +1,6 @@
 subdir('bmatest/')
 subdir('bmetest/')
+subdir('dual-core/')
 subdir('ecgtest/')
 subdir('hello-freertos/')
 subdir('hello-world/')
diff --git a/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core0.ld b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core0.ld
new file mode 100644
index 000000000..12c8bdaf9
--- /dev/null
+++ b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core0.ld
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * 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 MAXIM INTEGRATED 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.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ * $Date: 2018-12-03 22:29:43 +0000 (Mon, 03 Dec 2018) $ 
+ * $Revision: 39576 $
+ *
+ ******************************************************************************/
+
+/* SPID and SPIX Sections here are maximum possible sizes */
+/* If used, they should be adjusted for the external Flash/RAM size */
+MEMORY {
+    SPIX (rx)  : ORIGIN = 0x08000000, LENGTH = 128M
+    FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 256k
+    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k
+    SPID (r)   : ORIGIN = 0x80000000, LENGTH = 512M
+}
+
+SECTIONS {
+    .text :
+    {
+        _text = .;
+        KEEP(*(.isr_vector))
+        *(.text*)    /* program code */
+        *(.rodata*)  /* read-only data: "const" */
+        
+        KEEP(*(.init))
+        KEEP(*(.fini))
+
+        /* C++ Exception handling */
+        KEEP(*(.eh_frame*))
+        _etext = .;
+    } > FLASH
+    
+    /* This section will keep the SPIX data until loaded into the external device */
+    /* Upon initialization of SPIX (user code needs to do this) */
+    .xip_section :
+    {
+        KEEP(*(.xip_section*))
+    } > SPIX AT>FLASH
+
+    __load_start_xip = LOADADDR(.xip_section);
+    __load_length_xip = SIZEOF(.xip_section);
+
+    /* it's used for C++ exception handling      */
+    /* we need to keep this to avoid overlapping */
+    .ARM.exidx :
+    {
+        __exidx_start = .;
+        *(.ARM.exidx*)
+        __exidx_end = .;
+    } > FLASH
+
+    .data :
+    {
+        _data = ALIGN(., 4);
+        *(.data*)           /*read-write initialized data: initialized global variable*/
+        *(.spix_config*)    /* SPIX configuration functions need to be run from SRAM */
+        *(.flashprog*)      /* Flash program */
+        
+
+        /* These array sections are used by __libc_init_array to call static C++ constructors */
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        KEEP(*(SORT(.fini_array.*)))
+        KEEP(*(.fini_array))
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        _edata = ALIGN(., 4);
+    } > SRAM AT>FLASH
+    __load_data = LOADADDR(.data);
+
+    .bss :
+    {
+        . = ALIGN(4);
+        _bss = .;
+        *(.bss*)     /*read-write zero initialized data: uninitialzed global variable*/
+        *(COMMON)
+        _ebss = ALIGN(., 4);
+    } > SRAM
+
+    /* Setup the stack for Core 1, it will only be used if the user code
+     * includes a definition of Stack_Size_Core1, which defines the space
+     * reserved above the main core's stack for core 1's stack */
+
+    __StackTop_Core1 = ORIGIN(SRAM) + LENGTH(SRAM);
+    __StackLimit_Core1 = DEFINED(Stack_Size_Core1) ? __StackTop_Core1 - Stack_Size_Core1 : __StackTop_Core1;
+
+    /* Set stack top to end of RAM, and stack limit move down by Stack_Size. 
+     * If core 1 is used, set the stack to the bottom of Core 1's stack region */
+
+    __StackTop = DEFINED(Stack_Size_Core1) ? __StackLimit_Core1 : ORIGIN(SRAM) + LENGTH(SRAM);
+    __StackLimit = __StackTop - Stack_Size;
+
+    .heap (COPY):
+    {
+        . = ALIGN(4);
+        *(.heap*)
+        __HeapLimit = ABSOLUTE(__StackLimit);
+    } > SRAM
+
+    PROVIDE(__stack = __StackTop);
+
+    /* Check if data + heap + stack(s) exceeds RAM limit */
+    ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack")
+}
diff --git a/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core1.ld b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core1.ld
new file mode 100644
index 000000000..3978179d2
--- /dev/null
+++ b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/GCC/max32665_core1.ld
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * 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 MAXIM INTEGRATED 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.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ * $Date: 2018-12-03 22:29:43 +0000 (Mon, 03 Dec 2018) $ 
+ * $Revision: 39576 $
+ *
+ ******************************************************************************/
+
+/* SPID and SPIX Sections here are maximum possible sizes */
+/* If used, they should be adjusted for the external Flash/RAM size */
+MEMORY {
+    SPIX (rx)  : ORIGIN = 0x08000000, LENGTH = 128M
+    FLASH (rx) : ORIGIN = 0x10040000, LENGTH = 256k
+    SRAM (rwx) : ORIGIN = 0x20040000, LENGTH = 256k
+    SPID (r)   : ORIGIN = 0x80000000, LENGTH = 512M
+}
+
+SECTIONS {
+    .text :
+    {
+        _text = .;
+        KEEP(*(.isr_vector))
+        *(.text*)    /* program code */
+        *(.rodata*)  /* read-only data: "const" */
+        
+        KEEP(*(.init))
+        KEEP(*(.fini))
+
+        /* C++ Exception handling */
+        KEEP(*(.eh_frame*))
+        _etext = .;
+    } > FLASH
+    
+    /* This section will keep the SPIX data until loaded into the external device */
+    /* Upon initialization of SPIX (user code needs to do this) */
+    .xip_section :
+    {
+        KEEP(*(.xip_section*))
+    } > SPIX AT>FLASH
+
+    __load_start_xip = LOADADDR(.xip_section);
+    __load_length_xip = SIZEOF(.xip_section);
+
+    /* it's used for C++ exception handling      */
+    /* we need to keep this to avoid overlapping */
+    .ARM.exidx :
+    {
+        __exidx_start = .;
+        *(.ARM.exidx*)
+        __exidx_end = .;
+    } > FLASH
+
+    .data :
+    {
+        _data = ALIGN(., 4);
+        *(.data*)           /*read-write initialized data: initialized global variable*/
+        *(.spix_config*)    /* SPIX configuration functions need to be run from SRAM */
+        *(.flashprog*)      /* Flash program */
+        
+
+        /* These array sections are used by __libc_init_array to call static C++ constructors */
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        KEEP(*(SORT(.fini_array.*)))
+        KEEP(*(.fini_array))
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        _edata = ALIGN(., 4);
+    } > SRAM AT>FLASH
+    __load_data = LOADADDR(.data);
+
+    .bss :
+    {
+        . = ALIGN(4);
+        _bss = .;
+        *(.bss*)     /*read-write zero initialized data: uninitialzed global variable*/
+        *(COMMON)
+        _ebss = ALIGN(., 4);
+    } > SRAM
+
+    /* Setup the stack for Core 1, it will only be used if the user code
+     * includes a definition of Stack_Size_Core1, which defines the space
+     * reserved above the main core's stack for core 1's stack */
+
+    __StackTop_Core1 = ORIGIN(SRAM) + LENGTH(SRAM);
+    __StackLimit_Core1 = DEFINED(Stack_Size_Core1) ? __StackTop_Core1 - Stack_Size_Core1 : __StackTop_Core1;
+
+    /* Set stack top to end of RAM, and stack limit move down by Stack_Size. 
+     * If core 1 is used, set the stack to the bottom of Core 1's stack region */
+
+    __StackTop = DEFINED(Stack_Size_Core1) ? __StackLimit_Core1 : ORIGIN(SRAM) + LENGTH(SRAM);
+    __StackLimit = __StackTop - Stack_Size;
+
+    .heap (COPY):
+    {
+        . = ALIGN(4);
+        *(.heap*)
+        __HeapLimit = ABSOLUTE(__StackLimit);
+    } > SRAM
+
+    PROVIDE(__stack = __StackTop);
+
+    /* Check if data + heap + stack(s) exceeds RAM limit */
+    ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack")
+}
diff --git a/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/system_max32665_core1.c b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/system_max32665_core1.c
new file mode 100644
index 000000000..d8f211ff3
--- /dev/null
+++ b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/Source/system_max32665_core1.c
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * 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 MAXIM INTEGRATED 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.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ * $Date: 2018-11-07 19:23:01 +0000 (Wed, 07 Nov 2018) $
+ * $Revision: 39007 $
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "max32665.h"
+#include "mxc_sys.h"
+#include "gcr_regs.h"
+#include "icc_regs.h"
+#include "pwrseq_regs.h"
+
+// Backup mode entry point
+extern void Reset_Handler(void);
+
+extern void (* const __isr_vector[])(void);
+
+// Part defaults to HIRC/2 out of reset
+uint32_t SystemCoreClock = HIRC_FREQ >> 1; 
+
+__weak void SystemCoreClockUpdate(void)
+{
+    uint32_t base_freq, div, clk_src;
+
+    // Determine the clock source and frequency
+    clk_src = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_CLKSEL);
+    switch (clk_src)
+    {
+        case MXC_S_GCR_CLKCN_CLKSEL_HIRC:
+            base_freq = HIRC_FREQ;
+            break;
+        case MXC_S_GCR_CLKCN_CLKSEL_XTAL32M:
+            base_freq = XTAL32M_FREQ;
+            break;
+        case MXC_S_GCR_CLKCN_CLKSEL_LIRC8:
+            base_freq = LIRC8_FREQ;
+            break;
+        case MXC_S_GCR_CLKCN_CLKSEL_HIRC96:
+            base_freq = HIRC96_FREQ;
+            break;
+        case MXC_S_GCR_CLKCN_CLKSEL_HIRC8:
+            base_freq = HIRC8_FREQ;
+            break;
+        case MXC_S_GCR_CLKCN_CLKSEL_XTAL32K:
+            base_freq = XTAL32K_FREQ;
+            break;
+        default:
+	    // Values 001 and 111 are reserved, and should never be encountered.
+	    base_freq = HIRC_FREQ;
+            break;
+    }
+    // Clock divider is retrieved to compute system clock
+    div = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_PSC) >> MXC_F_GCR_CLKCN_PSC_POS;
+
+    SystemCoreClock = base_freq >> div;
+}
+
+/* This function is called before C runtime initialization and can be
+ * implemented by the application for early initializations. If a value other
+ * than '0' is returned, the C runtime initialization will be skipped.
+ *
+ * You may over-ride this function in your program by defining a custom 
+ *  PreInit(), but care should be taken to reproduce the initialization steps
+ *  or a non-functional system may result.
+ */
+__weak int PreInit(void)
+{
+    // Do nothing
+    return 0;
+}
+
+// This function can be implemented by the application to initialize the board
+__weak int Board_Init(void)
+{
+    // Do nothing
+    return 0;
+}
+
+/* This function is called just before control is transferred to main().
+ *
+ * You may over-ride this function in your program by defining a custom 
+ *  SystemInit(), but care should be taken to reproduce the initialization
+ *  steps or a non-functional system may result.
+ */
+__weak void SystemInit(void)
+{
+    /* Configure the interrupt controller to use the application vector 
+     * table in flash. Initially, VTOR points to the ROM's table.
+     */
+    SCB->VTOR = (unsigned long)&__isr_vector;
+
+    /* Enable FPU on Cortex-M4, which occupies coprocessor slots 10 & 11
+     * Grant full access, per "Table B3-24 CPACR bit assignments".
+     * DDI0403D "ARMv7-M Architecture Reference Manual"
+     */
+    SCB->CPACR |= SCB_CPACR_CP10_Msk | SCB_CPACR_CP11_Msk;
+    __DSB();
+    __ISB();
+
+    // Enable ICache1 Clock
+    MXC_GCR->perckcn1 &= ~(1 << 22);
+
+    // Invalidate cache and wait until ready
+    MXC_ICC1->invalidate = 1;
+    while (!(MXC_ICC1->cache_ctrl & MXC_F_ICC_CACHE_CTRL_CACHE_RDY));
+
+    // Enable Cache
+    MXC_ICC1->cache_ctrl |= MXC_F_ICC_CACHE_CTRL_CACHE_EN;
+
+    SystemCoreClockUpdate();
+
+    // No board init on core1
+    //Board_Init();
+}
diff --git a/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/meson.build b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/meson.build
index d71ad79f7..fb1b4eacb 100644
--- a/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/meson.build
+++ b/lib/sdk/Libraries/CMSIS/Device/Maxim/MAX32665/meson.build
@@ -1,3 +1,7 @@
+#############################################################
+# For applications using just core0 or not dual-binaries
+#############################################################
+
 sources = files(
   './Source/GCC/startup_max32665.S',
   './Source/system_max32665.c',
@@ -17,3 +21,51 @@ max32665_startup = declare_dependency(
     '--entry', 'Reset_Handler',
   ],
 )
+
+#############################################################
+# For core0 applications with dual-binaries
+#############################################################
+
+sources = files(
+  './Source/GCC/startup_max32665.S',
+  './Source/system_max32665.c',
+  './Source/heap.c',
+)
+
+lib = static_library(
+  'max32665-startup-core0',
+  sources,
+  dependencies: periphdriver,
+)
+
+max32665_startup_core0 = declare_dependency(
+  link_whole: lib,
+  link_args: [
+    '-T', meson.current_source_dir() + 'Source/GCC/max32665_core0.ld',
+    '--entry', 'Reset_Handler',
+  ],
+)
+
+#############################################################
+# For core1 applications with dual-binaries
+#############################################################
+
+sources = files(
+  './Source/GCC/startup_max32665.S',
+  './Source/system_max32665_core1.c',
+  './Source/heap.c',
+)
+
+lib = static_library(
+  'max32665-startup-core1',
+  sources,
+  dependencies: periphdriver,
+)
+
+max32665_startup_core1 = declare_dependency(
+  link_whole: lib,
+  link_args: [
+    '-T', meson.current_source_dir() + 'Source/GCC/max32665_core1.ld',
+    '--entry', 'Reset_Handler',
+  ],
+)
-- 
GitLab