#include "all-headers.h"

// MICROCONTROLLER SERIAL NUMBER

static uint32_t gMicrocontrollerSerialNumber ;
static uint32_t readMicrocontrollerSerialNumber (void) ;

// CLOCK SETTINGS
// The MCGCLOCKOUT frequency is given by (the 16 MHz quartz frequency is divided by 2 for the PPL)
//  MCGCLOCKOUT = 16 MHz / 2 * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1)

// CPU CLOCK
//  The CPU Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV1 + 1)
//
//  Here, CPU_MHZ is a given constant, so we only check that settings are correct by asserting:
//     CPU_MHZ * (MCG:C5:PRDIV + 1) * (SIM:CLKDIV1:OUTDIV1 + 1) = (16 MHz / 2) * (MCG:C6:VDIV + 16)

// BUS (peripheral) CLOCK
//  The peripheral Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV2 + 1)
//
//  Here, SIM:CLKDIV1:OUTDIV2 is a given constant, so we compute BUS_MHZ by:
//     BUS_MHZ = (16 MHz / 2) * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1) / (SIM:CLKDIV1:OUTDIV2 + 1)

// Flexbus CLOCK
//  The Flexbus Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV3 + 1)
//
//  Here, SIM:CLKDIV1:OUTDIV3 is a given constant, so we compute FLEXBUS_MHZ by:
//     FLEXBUS_MHZ = (16 MHz / 2) * (MCG:C6:VDIV + 16) /(MCG:C5:PRDIV + 1) / (SIM:CLKDIV1:OUTDIV3 + 1)

// Flash CLOCK
//  The FLASH Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV3 + 1)
//
//  Here, SIM:CLKDIV1:OUTDIV4 is a given constant, so we compute Flash Clock in kHz (result may not be integer):
//     FLASH_KHZ = (16000 kHz / 2) * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1) / (SIM:CLKDIV1:OUTDIV4 + 1)

// MICRO CONTROLLER REQUIREMENTS
// The clock dividers are programmed via the SIM module’s CLKDIV registers. Each divider is programmable from a
// divide-by-1 through divide-by-16 setting. The following requirements must be met when configuring the clocks
// for this device:
// 1. The core and system clock frequencies must be 180 MHz or slower in HSRUN, 120 MHz or slower in RUN.
// 2. The bus clock frequency must be programmed to 60 MHz or less in HSRUN or RUN, and an integer divide of the
//      core clock. The core clock to bus clock ratio is limited to a max value of 8.
// 3. The flash clock frequency must be programmed to 28 MHz or less, less than or equal to the bus clock, and an
//      integer divide of the core clock. The core clock to flash clock ratio is limited to a max value of 8.
// 4. The FlexBus clock frequency must be programmed to be less than or equal to the bus clock frequency. The
//      FlexBus also has pad interface restrictions that limits the maximum frequency. For this device the FlexBus
//      maximum frequency is 60 MHz. The core clock to FlexBus clock ratio is limited to a max value of 8.
// 5. Since SDRAMC and FlexBus both use CLKOUT, the same restrictions apply to the SDRAM controller as stated
//      for the FlexBus clock.

// SETTING SUMMARY
// F_CPU   MCG_C5   MCG_C6   SIM_CLKDIV1   SIM_CLKDIV1   SIM_CLKDIV1   SIM_CLKDIV1   BUS_MHZ   FLEXBUS    FLASH
// _MHZ    _PRDIV    _VDIV      _OUTDIV1      _OUTDIV2      _OUTDIV3      _OUTDIV4                _MHZ     _KHZ
//  240         0       14             0             3             0             7       60        240   30 000
//  216         0       11             0             1             0             7       54        216   27 000
//  192         0        8             0             1             0             6       28        192   27 428
//  180         1       29             0             1             0             6       60        180   25 714
//  168         0        5             0             2             0             5       56        168   28 000
//  144         0        2             0             1             0             4       28        144   28 800
//  120         1       14             0             1             0             4       60        120   24 000
//   96         1        8             0             1             0             2       24         96   24 000
//   72         1        2             0             0             0             2       36         72   24 000
//   48         1        8             1             1             1             3       48         48   24 000
//   24         1        8             3             3             3             3       24         24   24 000

// PRDIV SETTINGS
#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_MCG_C5_PRDIV = 0 ;
#elif CPU_MHZ == 240
static const uint32_t K_MCG_C5_PRDIV = 0 ;
#elif CPU_MHZ == 216
static const uint32_t K_MCG_C5_PRDIV = 0 ;
#elif CPU_MHZ == 192
static const uint32_t K_MCG_C5_PRDIV = 0 ;
#elif CPU_MHZ == 180
static const uint32_t K_MCG_C5_PRDIV = 1 ;
#elif CPU_MHZ == 168
static const uint32_t K_MCG_C5_PRDIV = 0 ;
#elif CPU_MHZ == 144
static const uint32_t K_MCG_C5_PRDIV = 0 ;
#elif CPU_MHZ == 120
static const uint32_t K_MCG_C5_PRDIV = 1 ;
#elif CPU_MHZ == 96
static const uint32_t K_MCG_C5_PRDIV = 1 ;
#elif CPU_MHZ == 72
static const uint32_t K_MCG_C5_PRDIV = 1 ;
#elif CPU_MHZ == 48
static const uint32_t K_MCG_C5_PRDIV = 1 ;
#elif CPU_MHZ == 24
static const uint32_t K_MCG_C5_PRDIV = 1 ;
#else
#error "CPU_MHZ has an invalid value"
static const uint32_t K_MCG_C5_PRDIV = 0 ;
#endif

// MCG:C6:VDIV SETTINGS
#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_MCG_C6_VDIV = 0 ;
#elif CPU_MHZ == 240
static const uint32_t K_MCG_C6_VDIV = 14 ;
#elif CPU_MHZ == 216
static const uint32_t K_MCG_C6_VDIV = 11 ;
#elif CPU_MHZ == 192
static const uint32_t K_MCG_C6_VDIV = 8 ;
#elif CPU_MHZ == 180
static const uint32_t K_MCG_C6_VDIV = 29 ;
#elif CPU_MHZ == 168
static const uint32_t K_MCG_C6_VDIV = 5 ;
#elif CPU_MHZ == 144
static const uint32_t K_MCG_C6_VDIV = 2 ;
#elif CPU_MHZ == 120
static const uint32_t K_MCG_C6_VDIV = 14 ;
#elif CPU_MHZ == 96
static const uint32_t K_MCG_C6_VDIV = 8 ;
#elif CPU_MHZ == 72
static const uint32_t K_MCG_C6_VDIV = 2 ;
#elif CPU_MHZ == 48
static const uint32_t K_MCG_C6_VDIV = 8 ;
#elif CPU_MHZ == 24
static const uint32_t K_MCG_C6_VDIV = 8 ;
#else
#error "CPU_MHZ has an invalid value"
static const uint32_t K_MCG_C6_VDIV = 0 ;
#endif

// SIM:CLKDIV1:OUTDIV1 SETTINGS
#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 0 ;
#elif CPU_MHZ == 48
static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 1 ;
#elif CPU_MHZ == 24
static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 3 ;
#else
static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 0 ; // 0 for all other settings
#endif


// SIM:CLKDIV1:OUTDIV2 SETTINGS (divisor for bus)

#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 0 ;
#elif CPU_MHZ == 240
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
#elif CPU_MHZ == 216
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
#elif CPU_MHZ == 192
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
#elif CPU_MHZ == 180
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 2 ;
#elif CPU_MHZ == 168
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 2 ;
#elif CPU_MHZ == 144
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 2 ;
#elif CPU_MHZ == 120
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
#elif CPU_MHZ == 96
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
#elif CPU_MHZ == 72
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
#elif CPU_MHZ == 48
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
#elif CPU_MHZ == 24
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
#else
#error "CPU_MHZ has an invalid value"
static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 0 ;
#endif


// BUS_MHZ
static const uint32_t BUS_MHZ = (16 / 2) * (K_MCG_C6_VDIV + 16) /(K_MCG_C5_PRDIV + 1) / (K_SIM_CLKDIV1_OUTDIV2 + 1) ;

uint32_t busMHZ (void) {
	return BUS_MHZ ;
}


// SIM:CLKDIV1:OUTDIV3 SETTINGS (divisor for Flexbus)


#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 0 ;
#elif CPU_MHZ == 48
static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 1 ;
#elif CPU_MHZ == 24
static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 3 ;
#else
static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 0 ; // 0 for all other settings
#endif


// FLEXBUS_MHZ


static const uint32_t FLEXBUS_MHZ = (16 / 2) * (K_MCG_C6_VDIV + 16) /(K_MCG_C5_PRDIV + 1) / (K_SIM_CLKDIV1_OUTDIV3 + 1) ;



uint32_t FlexBusMHZ (void) {
	return FLEXBUS_MHZ ;
}


// SIM:CLKDIV1:OUTDIV4 SETTINGS (divisor for Flash)


#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 0 ;
#elif CPU_MHZ == 240
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 7 ;
#elif CPU_MHZ == 216
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 7 ;
#elif CPU_MHZ == 192
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 6 ;
#elif CPU_MHZ == 180
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 6 ;
#elif CPU_MHZ == 168
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 5 ;
#elif CPU_MHZ == 144
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 4 ;
#elif CPU_MHZ == 120
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 4 ;
#elif CPU_MHZ == 96
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 3 ;
#elif CPU_MHZ == 72
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 2 ;
#elif CPU_MHZ == 48
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 3 ;
#elif CPU_MHZ == 24
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 3 ;
#else
#error "CPU_MHZ has an invalid value"
static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 0 ;
#endif


// FLASH CLOCK (in kHz)


static const uint32_t FLASH_KHZ = (16000 / 2) * (K_MCG_C6_VDIV + 16) / (K_MCG_C5_PRDIV + 1) / (K_SIM_CLKDIV1_OUTDIV4 + 1) ;



uint32_t FlashKHz (void) {
	return FLASH_KHZ ;
}


// USB CLOCK

// The USB module SHOULD be driven by a 48 MHz clock.
//
// For all CPU frequencies (but 216 MHz and 180 MHz), this clock is derived from MCGPLLCLK; the MCGPLLCLK is
// identical to MCGCLOCKOUT (as SIM_CLKDIV2_PLL_FLL_SEL=1). So:
//   USB_CLOCK = MCGCLOCKOUT * (K_SIM_CLKDIV2_USBFRAC + 1) / (K_SIM_CLKDIV2_USBDIV + 1)
// We check :
//   48 MHz == 16 MHz / 2 * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1) * (K_SIM_CLKDIV2_USBFRAC + 1) / (K_SIM_CLKDIV2_USBDIV + 1)
// So:
//   6 * (MCG:C5:PRDIV + 1) * (K_SIM_CLKDIV2_USBDIV + 1) == (MCG:C6:VDIV + 16) * (K_SIM_CLKDIV2_USBFRAC + 1)
//
// For 216 MHz and 180 MHz CPU frequencies, we use directly the built-in 48 MHz clock: SIM_CLKDIV2_PLL_FLL_SEL=3, with
// di divisor (K_SIM_CLKDIV2_USBFRAC=0 and K_SIM_CLKDIV2_USBDIV=0).

// USB SETTING SUMMARY

// F_CPU   SIM_CLKDIV2   SIM_CLKDIV2   SIM_SOPT2_
// _MHZ        _USBDIV      _USBFRAC    PLLFLLSEL
//  240              4             0            1
//  216              0             0            3
//  192              3             0            1
//  180              0             0            3
//  168              6             1            1
//  144              2             0            1
//  120              4             1            1
//   96              1             0            1
//   72              2             1            1
//   48              1             0            1
//   24              1             0            1

// SIM:SOPT2:PLLFLLSEL SETTINGS


#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 0 ;
#elif CPU_MHZ == 216
static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 3 ;
#elif CPU_MHZ == 180
static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 3 ;
#else
static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 1 ; // For all other settings
#endif


// SIM:CLKDIV2:USBFRAC SETTINGS


#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_SIM_CLKDIV2_USBFRAC = 0 ;
#elif CPU_MHZ == 168
static const uint32_t K_SIM_CLKDIV2_USBFRAC = 1 ;
#elif CPU_MHZ == 120
static const uint32_t K_SIM_CLKDIV2_USBFRAC = 1 ;
#elif CPU_MHZ == 72
static const uint32_t K_SIM_CLKDIV2_USBFRAC = 1 ;
#else
static const uint32_t K_SIM_CLKDIV2_USBFRAC = 0 ; // For all other settings
#endif


// SIM:CLKDIV2:USBDIV SETTINGS


#ifndef CPU_MHZ
#error "CPU_MHZ is not defined"
static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
#elif CPU_MHZ == 240
static const uint32_t K_SIM_CLKDIV2_USBDIV = 4 ;
#elif CPU_MHZ == 216
static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
#elif CPU_MHZ == 192
static const uint32_t K_SIM_CLKDIV2_USBDIV = 3 ;
#elif CPU_MHZ == 180
static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
#elif CPU_MHZ == 168
static const uint32_t K_SIM_CLKDIV2_USBDIV = 6 ;
#elif CPU_MHZ == 144
static const uint32_t K_SIM_CLKDIV2_USBDIV = 2 ;
#elif CPU_MHZ == 120
static const uint32_t K_SIM_CLKDIV2_USBDIV = 4 ;
#elif CPU_MHZ == 96
static const uint32_t K_SIM_CLKDIV2_USBDIV = 1 ;
#elif CPU_MHZ == 72
static const uint32_t K_SIM_CLKDIV2_USBDIV = 2 ;
#elif CPU_MHZ == 48
static const uint32_t K_SIM_CLKDIV2_USBDIV = 1 ;
#elif CPU_MHZ == 24
static const uint32_t K_SIM_CLKDIV2_USBDIV = 1 ;
#else
#error "CPU_MHZ has an invalid value"
static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
#endif


//  BOOT ROUTINE

void startPhase1 (void) {
	// Disable watchdog timer
	// These two instructions are required for unlocking watchdog timer
	WDOG_UNLOCK = 0xC520 ;
	WDOG_UNLOCK = 0xD928 ;
	// Disable watchdog timer
	WDOG_STCTRLH = 0 ;
	// Enable clocks to always-used peripherals
	SIM_SCGC3 = SIM_SCGC3_ADC1 | SIM_SCGC3_FTM2 | SIM_SCGC3_FTM3 ;
	SIM_SCGC5 = SIM_SCGC5_PORTA | SIM_SCGC5_PORTB | SIM_SCGC5_PORTC | SIM_SCGC5_PORTD | SIM_SCGC5_PORTE ;    // clocks active to all GPIO
	SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTF ;
	//  SCB_CPACR = 0x00F0_0000; // Enable floating point unit
	LMEM_PCCCR = LMEM_PCCCR_GO | LMEM_PCCCR_INVW1 | LMEM_PCCCR_INVW0 | LMEM_PCCCR_ENWRBUF | LMEM_PCCCR_ENCACHE ;
	// If the RTC oscillator isn't enabled, get it started early
	if ((RTC_CR & RTC_CR_OSCE) != 0) {
		RTC_SR = 0;
		RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE;
	}
	// Release I/O pins hold, if we woke up from VLLS mode
	if (PMC_REGSC & PMC_REGSC_ACKISO) {
		PMC_REGSC |= PMC_REGSC_ACKISO;
	}

	// Since this is a write once register, make it visible to all F_CPU's
	//    so we can into other sleep modes in the future at any speed
	SMC_PMPROT = SMC_PMPROT_AHSRUN | SMC_PMPROT_AVLP | SMC_PMPROT_ALLS | SMC_PMPROT_AVLLS;
	// PLL initialization (start in FEI mode)
	// Enable capacitors for crystal
	OSC_CR = OSC_CR_SC8P | OSC_CR_SC2P | OSC_CR_ERCLKEN;
	// Enable osc, 8-32 MHz range, low power mode
	MCG_C2 = MCG_C2_RANGE (2) | MCG_C2_EREFS;
	// Switch to crystal as clock source, FLL input = 16 MHz / 512
	MCG_C1 =  MCG_C1_CLKS(2) | MCG_C1_FRDIV(4);
	// Wait for crystal oscillator to begin
	while ((MCG_S & MCG_S_OSCINIT0) == 0) {}
	// Wait for FLL to use oscillator
	while ((MCG_S & MCG_S_IREFST) != 0) {}
	// Wait for MCGOUT to use oscillator
	while ((MCG_S & MCG_S_CLKST (3)) != MCG_S_CLKST(2)) {}
	// Now we're in FBE mode
	// Read microcontroller serial number
	//   This SHOULD be done in normal mode (not in HSRUN mode)
	//   We cannot store result in RAM, BSS section will be cleared (see below)
	const uint32_t serialNumber = readMicrocontrollerSerialNumber () ;
	// Turn on the PLL
	SMC_PMCTRL = SMC_PMCTRL_RUNM (3); // enter HSRUN mode
	while (SMC_PMSTAT != SMC_PMPROT_AHSRUN) {} // wait for HSRUN
	// Configure CPU clock
	MCG_C5 = K_MCG_C5_PRDIV ;
	MCG_C6 = MCG_C6_PLLS | K_MCG_C6_VDIV ;
	// Wait for PLL to start using xtal as its input
	while (!(MCG_S & MCG_S_PLLST)) {}
	// Wait for PLL to lock
	while (!(MCG_S & MCG_S_LOCK0)) {}
	// Now we're in PBE mode: program the clock dividers
	SIM_CLKDIV1 =
		SIM_CLKDIV1_OUTDIV1(K_SIM_CLKDIV1_OUTDIV1)
		| SIM_CLKDIV1_OUTDIV2(K_SIM_CLKDIV1_OUTDIV2)
		| SIM_CLKDIV1_OUTDIV3(K_SIM_CLKDIV1_OUTDIV3)
		| SIM_CLKDIV1_OUTDIV4(K_SIM_CLKDIV1_OUTDIV4)
		;
	SIM_CLKDIV2 =
		SIM_CLKDIV2_USBDIV (K_SIM_CLKDIV2_USBDIV)
		| K_SIM_CLKDIV2_USBFRAC
		;
	// Switch to PLL as clock source
	MCG_C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(4);
	// Wait for PLL clock to be used
	while ((MCG_S & MCG_S_CLKST (3)) != MCG_S_CLKST(3)) {}
	// USB clock
	SIM_SOPT2 =
		SIM_SOPT2_USBSRC
		| (K_SIM_SOPT2_PLLFLLSEL << 16)
		| SIM_SOPT2_TRACECLKSEL
		;
	// Clear '.bss' section
	extern uint32_t __bss_start ;
	extern const uint32_t __bss_end ;
	uint32_t * p = & __bss_start ;
	while (p != & __bss_end) {
		* p = 0 ;
		p ++ ;
	}
	// Copy .data section in RAM
	extern uint32_t __data_start ;
	extern const uint32_t __data_end ;
	extern uint32_t __data_load_start ;
	uint32_t * pSrc = & __data_load_start ;
	uint32_t * pDest = & __data_start ;
	while (pDest != & __data_end) {
		* pDest = * pSrc ;
		pDest ++ ;
		pSrc ++ ;
	}
	// Now, we can store serial number
	gMicrocontrollerSerialNumber = serialNumber ;
}


//   MICROCONTROLLER SERIAL NUMBER


static uint32_t readMicrocontrollerSerialNumber (void) {
	while ((FTFE_FSTAT & FTFE_FSTAT_CCIF) == 0) {} // Wait
	FTFE_FSTAT = FTFE_FSTAT_RDCOLERR | FTFE_FSTAT_ACCERR | FTFE_FSTAT_FPVIOL;
	// FTFE_FCCOB3 is a 8-bit register, followed by 3 other 8-bit registers, we write value by a single 32-bit access)
	FTFE_FCCOB_0_3 = 0x41070000 ;
	FTFE_FSTAT = FTFE_FSTAT_CCIF ;
	while ((FTFE_FSTAT & FTFE_FSTAT_CCIF) == 0) {} // Wait
	// Read serial number (FTFE_FCCOBB is a 8-bit register, followed by 3 other 8-bit registers, we get the serial number with a single 32-bit access)
	return FTFE_FCCOB_8_11 ;
}



uint32_t microcontrollerSerialNumber (void) {
	return gMicrocontrollerSerialNumber ;
}



void startPhase2 (void) {
	// Aller exécuter les routines d'initialisation de la section boot.routine.array
	extern void (* __boot_routine_array_start) (void) ;
	extern void (* __boot_routine_array_end) (void) ;
	void (* * ptr) (void) = & __boot_routine_array_start ;
	while (ptr != & __boot_routine_array_end) {
		(* ptr) () ;
		ptr ++ ;
	}
	// Run C++ global variable constructors
	extern void (* __constructor_array_start) (void) ;
	extern void (* __constructor_array_end) (void) ;
	ptr = & __constructor_array_start ;
	while (ptr != & __constructor_array_end) {
		(* ptr) () ;
		ptr ++ ;
	}
	// Aller exécuter les routines d'initialisation de la section init.routine.array
	extern void (* __init_routine_array_start) (void) ;
	extern void (* __init_routine_array_end) (void) ;
	ptr = & __init_routine_array_start ;
	while (ptr != & __init_routine_array_end) {
		(* ptr) () ;
		ptr ++ ;
	}
}