/*******************************************************************************
* Freescale Semiconductor Inc.
* (c) Copyright 2014 Freescale Semiconductor, Inc.
* ALL RIGHTS RESERVED.
********************************************************************************
Services performed by FREESCALE in this matter are performed AS IS and without
any warranty. CUSTOMER retains the final decision relative to the total design
and functionality of the end product. FREESCALE neither guarantees nor will be
held liable by CUSTOMER for the success of this project.
FREESCALE DISCLAIMS ALL WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY INCLUDING,
BUT NOT LIMITED TO, IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
A PARTICULAR PURPOSE ON ANY HARDWARE, SOFTWARE ORE ADVISE SUPPLIED 
TO THE PROJECT BY FREESCALE, AND OR NAY PRODUCT RESULTING FROM FREESCALE 
SERVICES. IN NO EVENT SHALL FREESCALE BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL 
DAMAGES ARISING OUT OF THIS AGREEMENT.
CUSTOMER agrees to hold FREESCALE harmless against any and all claims demands 
or actions by anyone on account of any damage, or injury, whether commercial,
contractual, or tortuous, rising directly or indirectly as a result 
of the advise or assistance supplied CUSTOMER in connection with product, 
services or goods supplied under this Agreement.
********************************************************************************
* File:             main.c
* Owner:            b05111
* Version:          0.0
* Date:             Nov-28-2014
* Classification:   General Business Information
* Brief:            pin toggle stationery for MPC5675KEVB
********************************************************************************
* Detailed Description: 
* Purpose of the example is to show how to generate Multi bit ECC error in
* internal SRAM or FLASH (user can choose it in the option at the end of main
* function) and how to handle this error with respect to constraints given by 
* MPC5675K architecture (ECSM/RGM/FCCU relation and ECC error handling through 
* reset). The example is only possible to run in internal_FLASH target. Power-
* -on-reset is required after downloading the code into MCU's flash. The example
* displays notices in the terminal window (setting specified below). No other 
* external connection is required.
* Example also shows impact of enabled cache (macro OPTIMIZATIONS_ON).
*
* ------------------------------------------------------------------------------
* Test HW:        MPC5675KEVB
* MCU:            PPC5675KFMMSJ in Lock-Step mode
* Fsys:           180/150 MHz CORE_CLK
* Debugger:       Lauterbach Trace32
*                 PeMicro USB-ML-PPCNEXUS
* Target:         RAM, internal_FLASH
* Terminal:       19200-8-no parity-1 stop bit-no flow control on eSCI_A
* EVB connection: default 
*
********************************************************************************
Revision History:
0.0     Nov-28-2014  b05111  Initial Version
0.1     Dec-01-2014  b05111  ECC with Cache enabled
0.2     Jun-04-2015  b05111  Lauterbach script chaged, minor edits
*******************************************************************************/

#include <stdio.h>
#include "MPC5675K.h"
#include "Exceptions.h"
#include "IntcInterrupts.h"
#include "uart.h"
#include "clock.h"
#include "Optimizations.h"
#include "e200z4_SPR_read_write_macros.h"

/*******************************************************************************
* External objects
*******************************************************************************/

/*******************************************************************************
* Global variables
*******************************************************************************/

// debugging variables
vint32_t critical_fault_count = 0;
vint32_t noncritical_fault_count = 0;
vint32_t safe_mode_count = 0;
vint32_t Machine_Check_handler_pass_count = 0;
vint32_t IVOR1_handler_pass_count = 0;

// RESET reasons
vuint16_t RGM_FES_reg = 0;
vuint16_t RGM_DES_reg = 0;
    
// counter
vuint32_t i;
 
// dummy variable
vuint32_t dummy;


/*******************************************************************************
* Constants and macros
*******************************************************************************/

/* Enable caches, branch prediction and optimize flash setting */
#define OPTIMIZATIONS_ON 1

#define FCCU_NCFK_KEY 0xAB3498FE
#define FCCU_CFK_KEY  0x618B7A50

/* FCCU keys */
#define FCCU_NCFK_KEY 0xAB3498FE
#define FCCU_CFK_KEY  0x618B7A50

/* CTRLK register OP-keys for FCCU configuration */
#define  KEY_OP1 0x913756AF
#define  KEY_OP2 0x825A132B
#define KEY_OP16 0x7ACB32F0
#define KEY_OP31 0x29AF8752

/* ECSM */
#define ECSM_ECR_EFNCR_MASK     0x01
#define ECSM_ECR_ERNCR_MASK     0x02
#define ECSM_ECR_EF1BR_MASK		0x10
#define ECSM_ECR_ER1BR_MASK     0x20

// Force RAM Continuous Noncorrectable Data Inversions
#define ECSM_EEGR_FRCNCI_MASK   0x0200
// Force RAM One Noncorrectable Data Inversions
#define ECSM_EEGR_FR1NCI_MASK   0x0100
// Force RAM Continuous 1-Bit Data Inversions
#define ECSM_EEGR_FRC1BI_MASK   0x2000
// Force RAM One 1-bit Data Inversion
#define ECSM_EEGR_FR11BI_MASK   0x1000

/*******************************************************************************
* Local types
*******************************************************************************/

/*******************************************************************************
* Local function prototypes
*******************************************************************************/
static void HW_init(void);
static void SysClk_init(void);
static void ModesAndClks_init(void);
static void PeriClkGen_init(void);
static void CU_init(void);
void DisableWatchdog(void);
static void ClearNCF(void);
static void ClearCF(void);
static void ClearFails(void);
static void ECSM_init(void);
static void FCCU_Alarm_Interrupt(void);
static void ME_Safe_Mode_Interrupt(void);
void IVOR1_handler(void);
static asm void Increment_MCSRR0_to_next_instruction(void);
static asm void ClearMCSR(void);
static void Machine_Check_handler(void);
static asm void ClearMSR_EE(void);
static asm void SetMSR_ME(void);
static void Generate_noncorrectable_RAM_ECC_error(void);
static void Generate_noncorrectable_FLASH_ECC_error(void);
static void Erase_Flash_Block_B0F0(void);


/*******************************************************************************
* Local variables
*******************************************************************************/

/* align this to a 0-modulo-8 address (aligned to 8 bytes) */
static vuint32_t RAM_test[2] __attribute__ ((aligned (8))) = 
{
    0xBABADEDA,
    0xCAFEBEEF
};

static vuint32_t RAM_test_read = 0;
static vuint32_t FLASH_test_read = 0;

/*******************************************************************************
Function Name : HW_init
Engineer      : b05111
Date          : Nov-10-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : initialization of the hw for the purposes of this example
Issues        : 
*******************************************************************************/
static void HW_init(void)
{
    DisableWatchdog();
    ClearFails();    
    SysClk_init();    

    #if OPTIMIZATIONS_ON
        CU_init();
        Optimizations();
    #endif 
}

/*******************************************************************************
Function Name : SysClk_init
Engineer      : b05111
Date          : Nov-10-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : 
Issues        : 
*******************************************************************************/
static void SysClk_init(void)
{
    ModesAndClks_init();
    PeriClkGen_init();
}

/*******************************************************************************
Function Name : ModesAndClks_init
Engineer      : b05111
Date          : Nov-10-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : - DRUN->RUN1->RUN0->RUN1->RUN1
                - enable CLKOUT
Issues        : 
*******************************************************************************/
static void ModesAndClks_init(void) 
{
    /* CLOCK ARCHITECTURE EXCERPT:

    2 MCU variants: a)CORE_CLK up to 180MHz (SYS_CLK up to 90)
                    b)CORE_CLK up to 150MHz (SYS_CLK up to 75)

    Clocking scheme based on NVUSRO non-volatile register (mirror in SSCM_UOPS):

    1) NVUSRO[CR] = 0b11 (default) - 1:2 Mode  fixed divider  additional divider
    =>      DRAMC_CLK    up to 180/150 MHz       1              none
            CORE_CLK     up to 180/150           1              none
            SYS_CLK      up to  90/75            2              none
            FLASH_CLK    up to  45/37.5          2              none
            PERI0_CLK    up to  90/75            1              CGM_SC_DC0
            PERI1_CLK    up to  45/37.5          2              CGM_SC_DC1

    2) NVUSRO[CR] = 0b10 - 1:3 Mode 
    =>      DRAMC_CLK    up to 180/150 MHz       1              none
            CORE_CLK     up to 180/150           1              none
            SYS_CLK      up to  60/50            3              none
            FLASH_CLK    up to  30/25            2              none
            PERI0_CLK    up to  60/50            1              CGM_SC_DC0
            PERI1_CLK    up to  30/25            2              CGM_SC_DC1
      
    3) NVUSRO[CR] = 0b01 - 1:1 Mode 
    =>      DRAMC_CLK    up to 180/150 MHz       1              none
            CORE_CLK     up to  90/75            2              none
            SYS_CLK      up to  90/75            2              none
            FLASH_CLK    up to  45/37.5          2              none
            PERI0_CLK    up to  90/75            1              CGM_SC_DC0
            PERI1_CLK    up to  45/37.5          2              CGM_SC_DC1

    General constraints:
    XOSC_CLK = 4-40 MHz, fvco = 256-512 MHz, DRAMC_CLK = 60-180 MHz, 
    CORE_CLK = 8-180 MHz, SYS_CLK = 8-90 MHz, FLASH_CLK = 4-45 MHz, 
    FMPLL0_CLK = 16-180 MHz, FMPLL1_1D0_CLK = 16-120 MHz, CLK_OUT = 2-60 MHz,
    FMPLL1_1D1_CLK = 42.66-80 MHz, PERI0_CLK = 8-90 MHz, PERI1_CLK = 4-45 MHz,
    MOTC_CLK = 4-120 MHz, FR_CLK = 40 or 80 MHz, CANPE_CLK = 4-40 MHz.
    
    Preconditions for code below:
    - XOSC = nounted 40MHz crystal (jumpers J42 and J43 in position 1-2)
    - Suspected MCU variant is: a)CORE_CLK up to 180MHz (SYS_CLK up to 90)
    - Suspected mode is: 1) NVUSRO[CR] = 0b11 (default) - 1:2 Mode
    - FMPLL0_CLK choosen as System Clock Selector Input Clock */

    int32_t cnt = 0;
    
    /* Enable DRUN, RUN0, RUN1 SAFE, RESET modes */
    ME.MER.R = 0x0000003D;
    
    /* Mode Transition to enter RUN1 mode:    
       RUN1 cfg: 16MHzIRCON,OSC0ON,PLL0OFF,PLL1OFF,syclk=16MIRC */
    ME.RUN[1].R = 0x001F0030;
    ME.MCTL.R = 0x50005AF0;             // Enter RUN1 Mode & Key       
    ME.MCTL.R = 0x5000A50F;             // Enter RUN1 Mode & Inverted Key
    while(0 == ME.GS.B.S_XOSC) {};      // Wait for mode entry to complete
    while(1 == ME.GS.B.S_MTRANS) {}     // Wait for mode transition to complete
    while(5 != ME.GS.B.S_CURRENTMODE) {};   // Check RUN1 mode has been entered 
    
 
    /* Initialize PLL before turning it on:
       FMPLL0_CLK = XOSC_CLK*NDIV/IDF/ODF
       fvco must be from 256 MHz to 512 MHz
       we want fsys = 180 MHz
       fvco = FMPLL0_CLK * ODF = 180 MHz * 2 = 360 MHz => OK
       FMPLL0_CLK =  40*36/4/2 = 180 MHz
       FMPLL0_CLK choosen as System Clock Selector Input Clock */

    CGM.AC3_SC.R = 0x01000000;  // Select Xosc as PLL0 source clock
    CGM.AC4_SC.R = 0x01000000;  // Select Xosc as PLL1 source clock

#if defined(CORE_CLOCK_180MHz)
    /* FMPLL0_CLK = 180 MHz */
    CGM.FMPLL[0].CR.B.IDF = 0x3;  // FMPLL0 IDF=3 --> divide by 4
    CGM.FMPLL[0].CR.B.ODF = 0x0;  // FMPLL0 ODF=0 --> divide by 2
    CGM.FMPLL[0].CR.B.NDIV = 36;  // FMPLL0 NDIV=36 --> divide by 36

#elif defined(CORE_CLOCK_150MHz)
    /* FMPLL0_CLK = 150 MHz */
    CGM.FMPLL[0].CR.B.IDF = 0x5;  // FMPLL0 IDF=5 --> divide by 6
    CGM.FMPLL[0].CR.B.ODF = 0x0;  // FMPLL0 ODF=0 --> divide by 2
    CGM.FMPLL[0].CR.B.NDIV = 45;  // FMPLL0 NDIV=45 --> divide by 45
								
#else // error
    while (1) { asm(nop); }
#endif
    
    /* FMPLL1_1D0_CLK = 120 MHz */
    CGM.FMPLL[1].CR.B.IDF = 0x5;  // FMPLL0 IDF=5 --> divide by 8
    CGM.FMPLL[1].CR.B.ODF = 0x1;  // FMPLL0 ODF=1 --> divide by 4
    CGM.FMPLL[1].CR.B.NDIV = 72;  // FMPLL0 NDIV=72 --> divide by 64

    /* enable progressive clock switching */ 
    /* Note: PHI_PCS output only on PLL_0 */
    CGM.FMPLL[0].CR.B.EN_PLL_SW = 1; 	
        
    ME.RUNPC[0].R = 0x000000FE;  // peripheral run in all modes
    ME.RUNPC[1].R = 0x00000000;  // peripheral frozen in all modes
    ME.LPPC[0].R = 0x00000000;   // disable peripheral run in LP modes
        
    /* disable all clocks that ca be disabled */
    CGM.SC_DC0.R = 0x00000000;   // disable peripheral set 0/1 clocks
        // note: header file defines this register different way than RM
        // SC_DC0 compounds here from SC_DC0 + SC_DC1 + 16 zero padding
    CGM.AC0_DC0.R = 0x00000000;  // disable Motor control clock
    CGM.AC1_DC0.R = 0x00000000;  // disable FlexRay clock
    CGM.AC2_DC0.R = 0x00000000;  // disable FlexCAN clock

    /* Mode Transition to enter RUN0 mode:
       RUN0 cfg: 16MHzIRCON,OSC0ON,PLL0ON,PLL1off,syclk=16M IRC */
    ME.RUN[0].R = 0x001F0070;           
    ME.MCTL.R = 0x40005AF0;             // Enter RUN0 Mode & Key
    ME.MCTL.R = 0x4000A50F;             // Enter RUN0 Mode & Inverted Key    
    while (1 == ME.GS.B.S_MTRANS) {}    // Wait for mode transition to complete
    while(4 != ME.GS.B.S_CURRENTMODE) {};   // Check RUN0 mode has been entered
    
    /* 1 SRAM waistate (default) */
    ECSM_0.MUDCR.R = 0x40000000; 
    
    /* max divider when switching FMPLL0_CLK from IRC to PLL0 */
    CGM.FMPLL[0].CR.B.ODF = 0x3;   // FMPLL0 ODF=3 --> divide by 16  
    
    /* Mode Transition to enter RUN1 mode:
       RUN1 cfg: 16MHzIRCON,OSC0ON,PLL0ON,PLL1off,syclk=PLL0 */
    ME.RUN[1].R = 0x001F0074;           
    ME.MCTL.R = 0x50005AF0;             // Enter RUN1 Mode & Key
    ME.MCTL.R = 0x5000A50F;             // Enter RUN1 Mode & Inverted Key
    while(1 == ME.GS.B.S_MTRANS) {}     // Wait for mode transition to complete
    while(5 != ME.GS.B.S_CURRENTMODE) {};   // Check RUN1 mode has been entered
    
    CGM.FMPLL[0].CR.B.ODF = 0x2;   // FMPLL0 ODF=2 --> divide by 8
    CGM.FMPLL[0].CR.B.ODF = 0x1;   // FMPLL0 ODF=1 --> divide by 4
    
    /* now manually tested delay for the VDD reg to stabilize ....
       otherwise on the EVB, low voltage 1.2VDD destructive reset might occur */   
    for(cnt=0;cnt<275;cnt++) {} 
    CGM.FMPLL[0].CR.B.ODF = 0x0;   // FMPLL0 ODF=0 --> divide by 2

    /* Mode Transition to enter RUN1 mode:   
       RUN1 cfg: 16MHzIRCON,OSC0ON,PLL0ON,PLL1ON,syclk=PLL0 */ 
    ME.RUN[1].R = 0x001F00F4;      
    ME.MCTL.R = 0x50005AF0;             // Enter RUN1 Mode & Key
    ME.MCTL.R = 0x5000A50F;             // Enter RUN1 Mode & Inverted Key
    while(1 == ME.GS.B.S_MTRANS) {}     // Wait for mode transition to complete
    while(5 != ME.GS.B.S_CURRENTMODE) {};   // Check RUN1 mode has been entered
    
    /* peri set 0 divide by 1, per set1 divide by 2 */    
    CGM.SC_DC0.R = 0x80810000;
        // note: header file defines this register different way than RM
        // SC_DC0 compounds here from SC_DC0 + SC_DC1 + 16 zero padding
    
    /* set CLKOUT divider of 4 */
    CGM.OCDS_SC.R = 0x32000000;   // div by 4, system FMPLL
    CGM.OC_EN.B.EN = 1; 	      // enable CLKOUT signal
    
    /* enable CLK_OUT on ball E20 */
    /* ALT1 - PCR[233] - PA = 0b01 */
    SIU.PCR[233].R = 0x0600;
}

/*******************************************************************************
Function Name : PeriClkGen_init
Engineer      : b08110
Date          : Oct-19-2011
Parameters    : 
Modifies      : 
Returns       : 
Notes         : - Enable auxiliary clock 1-2. from PLL0
Issues        : 
*******************************************************************************/
static void PeriClkGen_init(void) 
{
    CGM.AC0_SC.R = 0x05000000;  /* Select PLL1 for Motor Control Clock  */
    CGM.AC0_DC0.R = 0x80800000;  /* Enable Motor Control clk div by 1 */
    CGM.AC1_SC.R = 0x04000000;  /* Select PLL0 for aux clk 1  */
    CGM.AC1_DC0.R = 0x80000000;  /* Enable aux clk 1 div by 1 */
    CGM.AC2_SC.R = 0x04000000;  /* Select PLL0 for aux clk 2  */
    CGM.AC2_DC0.R = 0x80000000;  /* Enable aux clk 2 div by 1 */
}


/*******************************************************************************
Function Name : CU_init
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : guarantees the same content between SRAM/FLASH and cache      
Issues        : 
*******************************************************************************/
static void CU_init(void)
{
 
    /* enable indication eDMA -> CCU */
    #if (LOCKSTEP_MODE)
        EDMA_0.DMAGPOR.R = 0xffffffff; // writes from DMA are "global"
    #else // DPM mode 
        EDMA_0.DMAGPOR.R = 0xffffffff; // writes from DMA are "global"
        EDMA_1.DMAGPOR.R = 0xffffffff; // writes from DMA are "global"    
    #endif 

    /* enable cache snooping for both cores and both eDMA engines */
    CU.CESR.R = 0x0000F001;

}


/*******************************************************************************
Function Name : DisableWatchdog
Engineer      : b08110
Date          : Jun-23-2010
Parameters    : 
Modifies      : 
Returns       : 
Notes         : - disable SWT functionality
Issues        : 
*******************************************************************************/
void DisableWatchdog(void) 
{
    SWT_0.SR.R = 0x0000c520;     /* Write keys to clear soft lock bit */
    SWT_0.SR.R = 0x0000d928; 
    SWT_0.CR.R = 0x8000010A;     /* Clear watchdog enable (WEN) */
    
    /* e200 Core Watchdog Timer */
    asm
    {
        li  r3, 0
        mtspr   340, r3
    }
}


/*******************************************************************************
Function Name : ClearNCF
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : 
Issues        : 
*******************************************************************************/
static void ClearNCF(void)
{
    uint32_t i,b[4];
    for(i=0;i<1;i++)
    {
        FCCU.NCFK.R = FCCU_NCFK_KEY;
        FCCU.NCFS0.R = 0xFFFFFFFF;
        while(FCCU.CTRL.B.OPS != 0x3)
        {
        
        };              /* wait for the completion of the operation */
        b[i]=FCCU.NCFS0.R;
    }
}


/*******************************************************************************
Function Name : ClearCF
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : 
Issues        : 
*******************************************************************************/
static void ClearCF(void)
{
    uint32_t i,a[4];
    for(i=0;i<2;i++)
    {
        FCCU.CFK.R = FCCU_CFK_KEY;
   
        FCCU.CFS[i].R = 0xFFFFFFFF;
  
        while(FCCU.CTRL.B.OPS != 0x3)
        {
            
        };      /* wait for the completion of the operation */

        a[i]=FCCU.CFS[i].R;
    }
}


/*******************************************************************************
Function Name : ClearFails
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : 
Issues        : 
*******************************************************************************/
static void ClearFails(void)
{
    uint16_t reset_register;
    
    if(RGM.FES.B.F_FCCU_SAFE)
    {
        reset_register = RGM.FES.R;
        ME.IMTS.R = 0x00000001;
        ClearCF();
        ClearNCF();
        
        RGM.FES.R = 0xFFFF;
        RGM.DES.R = 0xFFFF;
        
        /* re-enter DRUN */
        ME.MCTL.R = 0x30005AF0; /* Enter DRUN Mode & Key */        
        ME.MCTL.R = 0x3000A50F; /* Enter DRUN Mode & Inverted Key */
    }
}


/*******************************************************************************
Function Name : ECSM_init
Engineer      : b05111
Date          : Aug-21-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : initialization of the ECSM module
Issues        : 
*******************************************************************************/
static void ECSM_init(void)
{
 
    /* enable RAM ECC error reporting */
    ECSM_0.ECR.R = (uint8_t) ECSM_ECR_EFNCR_MASK | // non-correctable FLASH error
                           ECSM_ECR_ERNCR_MASK ; // non-correctable RAM error                          

}


/*******************************************************************************
Function Name : FCCU_Alarm_Interrupt
Engineer      : b05111
Date          : Apr-12-2012
Parameters    : 
Modifies      : 
Returns       : 
Notes         : 
Issues        : 
*******************************************************************************/
static void FCCU_Alarm_Interrupt(void)
{
   noncritical_fault_count++;
   ClearNCF();    
}


/*******************************************************************************
Function Name : ME_Safe_Mode_Interrupt
Engineer      : b05111
Date          : Apr-12-2012
Parameters    : 
Modifies      : 
Returns       : 
Notes         : 
Issues        : 
*******************************************************************************/
static void ME_Safe_Mode_Interrupt(void)
{

    #define FES_F_FCCU_SAFE 0x0080
    #define ME_IS_I_SAFE 0x00000002
    
    safe_mode_count++;  
    
    /* clear functional event in RGM (safe mode) */
    RGM.FES.R = FES_F_FCCU_SAFE;
  
    /* clear interrupt flag in ME */
    ME.IS.R = ME_IS_I_SAFE;

    /* configure DRUN same way as RUN1 */
    ME.DRUN.R = 0x001F00F4;
    
    /* select DRUN */          
    ME.MCTL.R = 0x30005AF0;         
    ME.MCTL.R = 0x3000A50F;               
    
    while (1 == ME.GS.B.S_MTRANS) {} // Wait for mode transition to complete
    while (3 != ME.GS.B.S_CURRENTMODE) {};    
    
    /* Mode Transition to enter RUN1 mode: */
    // Enter RUN1 Mode & Key
    ME.MCTL.R = 0x50005AF0;
    // Enter RUN1 Mode & Inverted Key
    ME.MCTL.R = 0x5000A50F;
    // Wait for mode transition to complete
    while (1 == ME.GS.B.S_MTRANS) {}
    // Check RUN1 mode has been entered
    while (5 != ME.GS.B.S_CURRENTMODE) {};
  
  
    // get FCCU back to normal state
	#define  KEY_OP2 0x825A132B
    FCCU.CTRLK.R = KEY_OP2;
    FCCU.CTRL.R = 2;         
}


/*******************************************************************************
Function Name : IVOR1_handler
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : Function handles IVOR1 exception.        
Issues        : For z4 and z7:
                -  __declspec(interrupt machine)
                - mcsrr0 register increment
                For z0, z1, z3, z6:
                - __declspec(interrupt critical)
                - csrr0 register increment
*******************************************************************************/
#pragma push /* Save the current state */
#pragma force_active on
#pragma function_align 16 /* We use 16 bytes alignment for Exception handlers */
__declspec(interrupt machine)
void IVOR1_handler(void)
{  
    
    Machine_Check_handler();
    
    Increment_MCSRR0_to_next_instruction();
    
    ClearMCSR();
    
    IVOR1_handler_pass_count++;

}
#pragma force_active off
#pragma pop


/*******************************************************************************
Function Name : Increment_MCSRR0_to_next_instruction
Engineer      : b05111
Date          : Sep-19-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : - based on algorithm described in AN4648
                - applicable for IVOR1 (stores address to MCSRR0)                              
Issues        : 
*******************************************************************************/
#if VLE_IS_ON // for VLE code 
static asm void Increment_MCSRR0_to_next_instruction(void)
{
    /* prolog */
    fralloc
    
    /* MCSRR0->r5 */
    mfmcsrr0 r5
    
    /* determine opcode @ MCSRR0 */
    se_lhz r4,0(r5)
    
    /* check bit 31,28 only*/
    e_andi. r3,r4,0x9000
    e_cmpli 0x0,r3,0x1000 
    
    e_bne __machine_check_adjust_for_16bit_opcode
    
        /* 0xx1 => 32 bit*/
        se_addi r5,2
    
    __machine_check_adjust_for_16bit_opcode:
    
        /* all others just 16 bit long*/
        se_addi r5,2 
        
        /* save adjusted return address*/
        mtmcsrr0 r5 
    
    
    /* epilog */
    frfree
    blr   
}
#else //BookE
static asm void Increment_MCSRR0_to_next_instruction(void)
{
    /* prolog */
    fralloc
    
    /* MCSRR0->r5 */
    mfmcsrr0 r5
    
    /* for BookE, all instructions are 32 bit long */
    se_addi r5,4
        
    /* save adjusted return address*/
    mtmcsrr0 r5 
    
    /* epilog */
    frfree
    blr 
}
#endif


/*******************************************************************************
Function Name : ClearMCSR
Engineer      : b05111
Date          : Sep-19-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : When MSR[ME] is set, error flags must be cleared to prevent 
                machine check exception to recall.                                 
Issues        : 
*******************************************************************************/
static asm void ClearMCSR(void)
{
    /* prolog */
    fralloc
    
    /* load mask */   
    lis r4, 0xFFFF
    ori r4, r4, 0xFFFF
    
    /* Clear MCSR */
    mtmcsr r4
    
    /* epilog */
    frfree
    blr   
}


/*******************************************************************************
Function Name : Machine_Check_handler
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : Function handles IVOR1 exception.        
Issues        : 
*******************************************************************************/
static void Machine_Check_handler(void)
{
    // must be static local or global variable
    static vuint32_t address_capture;    // MCAR
    static vuint32_t syndrome_register;  // MCSR
    
    READ_FROM_SPR(SPR_MCAR,address_capture);
    READ_FROM_SPR(SPR_MCSR,syndrome_register);
    
    printf("Multibit ECC error found on address 0x%X ", address_capture);
    printf("with syndrome 0x%X\r\n", syndrome_register);

    Machine_Check_handler_pass_count++;
    critical_fault_count++;
    ClearCF();
}


/*******************************************************************************
Function Name : ClearMSR_EE
Engineer      : b05111
Date          : Sep-19-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : Negates the MSR[EE].                                   
Issues        : 
*******************************************************************************/
static asm void ClearMSR_EE(void)
{
    /* prolog */
    fralloc
    
    /* read spr MSR */
    mfmsr r3  
    
    /* load mask to negate the EE bit */   
    lis r4, 0xFFFF
    ori r4, r4, 0x7FFF
    
    /* clear EE bit */
    and r3, r3, r4
    
    /* write back to MSR */
    mtmsr r3
    
    /* epilog */
    frfree
    blr   
}


/*******************************************************************************
Function Name : SetMSR_ME
Engineer      : b05111
Date          : Sep-19-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : Asserts the MSR[ME].                                   
Issues        : 
*******************************************************************************/
static asm void SetMSR_ME(void)
{
    /* prolog */
    fralloc
    
    /* read spr MSR */
    mfmsr r3
    
    /* load mask to assert the ME bit */   
    lis r4, 0x0000
    ori r4, r4, 0x1000
    
    /* set ME bit */
    or r3, r3, r4
    
    /* write back to MSR */
    mtmsr r3
    
    /* epilog */
    frfree
    blr   
}


/*******************************************************************************
Function Name : Generate_noncorrectable_RAM_ECC_error
Engineer      : b05111
Date          : Aug-21-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : generates 2-bit ECC error in RAM using the ECSM_EEGR register
Issues        : ECC is being calculated above 64-bit word. RAM[0] of the odd 
                bank means bit 0, RAM[0] of the even bank means bit 32
*******************************************************************************/
static void Generate_noncorrectable_RAM_ECC_error(void)
{
       
    /* Force internal SRAM one non-correctable data error */
    ECSM_0.EEGR.R = (uint16_t)(ECSM_EEGR_FR1NCI_MASK | 32);
    
    /* write to internal SRAM - this generates the wrong data */
    RAM_test[0] = 0xCAFEBEEF;

    printf("SRAM 2b ECC error injected\r\n");
    printf("Now check read of affected area\r\n");
    printf("\r\n");
    
    /* if data cache enabled, flush it (here by re-initialization) */
    #if OPTIMIZATIONS_ON
        Optimizations();
    #endif 
        
    /* now here the ECC is checked and non-correctable error found */
    RAM_test_read = RAM_test[0];  // error caused by read
    RAM_test_read = RAM_test[1];
}


/*******************************************************************************
Function Name : Generate_noncorrectable_FLASH_ECC_error
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         : Generates 2b ECC error into data flash        
Issues        : 
*******************************************************************************/
static void Generate_noncorrectable_FLASH_ECC_error(void)
{
    #define DATA_FLASH_start   0x00800000
    #define DATA_FLASH_end     0x0080FFFF
    #define DATA_FLASH_addr_0  0x00800008
    #define DATA_FLASH_addr_1  0x0080000C
    
    /* password to unlock space array */
    #define FLASH_LMLR_PASSWORD   0xA1A11111  // Low/Mid
    #define FLASH_HLR_PASSWORD    0xB2B22222  // High
    #define FLASH_SLMLR_PASSWORD  0xC3C33333  // Secondary Low/Mid
    
    /* enable low address space */	
    DFLASH_0.LML.R = FLASH_LMLR_PASSWORD;
    DFLASH_0.LML.R = 0x00000000;              // unlock all LLK3-LLK0
    DFLASH_0.SLL.R = FLASH_SLMLR_PASSWORD;
    DFLASH_0.SLL.R = 0x00000000;              // unlock all SLLK3-SLLK0

    /* step1. erase B0F0 (0x00800000-0x00803FFF) */
    DFLASH_0.MCR.B.ERS = 1;                   // select operation (erase)
    DFLASH_0.LMS.R = 0x00000001;              // select B0F0 block
    *((unsigned int*) DATA_FLASH_addr_0) = 0xFFFFFFFF;   // interlock write
    DFLASH_0.MCR.B.EHV = 1;                   // operation start (erase)
    while(DFLASH_0.MCR.B.DONE == 0){};        // wait for DONE
    DFLASH_0.MCR.B.EHV = 0;                   // operation end
    DFLASH_0.MCR.B.ERS = 0;                   // deselect operation
    
    /* step2. program data */
    DFLASH_0.MCR.B.PGM = 1;                   // select operation (program)
    *((unsigned int*) DATA_FLASH_addr_0) = 0x00450000; // first write
    DFLASH_0.MCR.B.EHV = 1;                   // start the program operation
    while(DFLASH_0.MCR.B.DONE == 0){};        // wait for DONE
    DFLASH_0.MCR.B.EHV = 0;                   // operation end
    *((unsigned int*) DATA_FLASH_addr_1) = 0x00000000; // additional write
    DFLASH_0.MCR.B.EHV = 1;                   // start the program operation
    while(DFLASH_0.MCR.B.DONE == 0){};        // wait for DONE
    DFLASH_0.MCR.B.EHV = 0;                   // operation end
    DFLASH_0.MCR.B.PGM = 0;                   // deselect operation
    
    /* step3. over-program data - this generates ECC error */
    DFLASH_0.MCR.B.PGM = 1;                   // select operation (program)
    *((unsigned int*) DATA_FLASH_addr_0) = 0x00580000; // first write
    DFLASH_0.MCR.B.EHV = 1;                   // start the program operation
    while(DFLASH_0.MCR.B.DONE == 0){};        // wait for DONE
    DFLASH_0.MCR.B.EHV = 0;                   // operation end
    *((unsigned int*) DATA_FLASH_addr_1) = 0x00000000; // additional write
    DFLASH_0.MCR.B.EHV = 1;                   // start the program operation
    while(DFLASH_0.MCR.B.DONE == 0){};        // wait for DONE
    DFLASH_0.MCR.B.EHV = 0;                   // operation end
    DFLASH_0.MCR.B.PGM = 0;                   // deselect operation
    
    printf("FLASH 2b ECC error injected\r\n");
    printf("Now check read of affected area\r\n");
    printf("\r\n");
    
    /* if data cache enabled, flush it (here by re-initialization) */
    //#if OPTIMIZATIONS_ON
    //    Optimizations();
    //#endif 
    
    /* now here the ECC is checked and non-correctable error found */
    FLASH_test_read = *((unsigned int*) DATA_FLASH_addr_0);
    FLASH_test_read = *((unsigned int*) DATA_FLASH_addr_1);

}


/*******************************************************************************
Function Name : Erase_Flash_Block_B0F0
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         :                          
Issues        : 
*******************************************************************************/
static void Erase_Flash_Block_B0F0(void)
{
    #define DATA_FLASH_start   0x00800000
    #define DATA_FLASH_end     0x0080FFFF
    //#define DATA_FLASH_addr_0  0x00800000
    //#define DATA_FLASH_addr_1  0x00800004
    
    /* password to unlock space array */
    #define FLASH_LMLR_PASSWORD   0xA1A11111  // Low/Mid
    #define FLASH_HLR_PASSWORD    0xB2B22222  // High
    #define FLASH_SLMLR_PASSWORD  0xC3C33333  // Secondary Low/Mid
    
    /* enable low address space */	
    DFLASH_0.LML.R = FLASH_LMLR_PASSWORD;
    DFLASH_0.LML.R = 0x00000000;              // unlock all LLK3-LLK0
    DFLASH_0.SLL.R = FLASH_SLMLR_PASSWORD;
    DFLASH_0.SLL.R = 0x00000000;              // unlock all SLLK3-SLLK0

    /* step1. erase B0F0 (0x00800000-0x00803FFF) */
    DFLASH_0.MCR.B.ERS = 1;                   // select operation (erase)
    DFLASH_0.LMS.R = 0x00000001;              // select B0F0 block
    *((unsigned int*) DATA_FLASH_addr_0) = 0xFFFFFFFF;   // interlock write
    DFLASH_0.MCR.B.EHV = 1;                   // operation start (erase)
    while(DFLASH_0.MCR.B.DONE == 0){};        // wait for DONE
    DFLASH_0.MCR.B.EHV = 0;                   // operation end
    DFLASH_0.MCR.B.ERS = 0;                   // deselect operation
}


/*******************************************************************************
* Global functions
*******************************************************************************/

/*******************************************************************************
Function Name : main
Engineer      : b05111
Date          : Nov-28-2014
Parameters    : 
Modifies      : 
Returns       : 
Notes         :                          
Issues        : 
*******************************************************************************/
int32_t main(void) 
{
    #define RGM_FES_F_FL_ECC_RCC 0x0400
    
    #define CODE_FLASH_start  0x00000000
    #define CODE_FLASH_end    0x001FFFFF
    
    #define DATA_FLASH_start  0x00800000
    #define DATA_FLASH_end    0x0080FFFF   
    
    /* Save RGM status register before initialization for subsequent usage */
    // Note: Multi-bit ECC also cause FCCU CF16 and CF17
    RGM_FES_reg = RGM.FES.R;
    RGM_DES_reg = RGM.DES.R;
    
    vint32_t counter = 0;
    
    /* Initialize the MCU */
    HW_init();
    
    /* */
    SetMSR_ME();
    ClearMCSR();
    
    /* check ECC error */
    if(RGM_FES_reg & RGM_FES_F_FL_ECC_RCC)
    {
        printf("Functional RESET due to Multi-Bit ECC error\r\n");  
        printf("Start flash scan...\r\n");
        
        /* Scan the content of flash memory */
        // Possible fault will lead in IVOR1
        // Shadow block omitted
        for (i=CODE_FLASH_start; i<CODE_FLASH_end; i=i+4)
        {
            dummy = (*(uint32_t *) i);
        }
        
        for (i=DATA_FLASH_start; i<DATA_FLASH_end; i=i+4)
        {
            //printf("%X\r\n", i);
            dummy = (*(uint32_t *) i);
        }
        
        // check whether there was IVOR0 exception during scan
        if (Machine_Check_handler_pass_count == 0)
        {
            printf("No FLASH ECC error has been found => \r\n");
            printf("ECC error was in SRAM and has already been "); 
            printf("corrected during SRAM init sequence\r\n");
            printf("The application can continue\r\n");
            printf("Have a nice day\r\n");
            
            // Loop forever
            for (;;) 
            {
                asm (nop);
            }
            
        }
        else
        {
            printf("Number of FLASH ECC error founded: ");
            printf("%d\r\n", critical_fault_count);
            printf("The application should be re-flashed\r\n");
            printf("\r\n");
            
            printf("Now erase block B0F0 of data flash as example of data correction\r\n");
            Erase_Flash_Block_B0F0();
            printf("Done...\r\n");
            printf("Have a nice day\r\n");
            
            // Loop forever
            for (;;) 
            {
                asm (nop);
            }
        }
        
    }

    /* unmask safe mode interrupt */
    ME.IM.R = 0x00000002; 
    
    /* */
    SetMSR_ME();

    /* Install ISRs into the interrupt vector table */
    INTC_InstallINTCInterruptHandler(FCCU_Alarm_Interrupt, 250, 8);
    INTC_InstallINTCInterruptHandler(ME_Safe_Mode_Interrupt, 51, 7);
    
    /* lower current INTC priority to start INTC interrupts */
    INTC_0.CPR_PRC0.R = 0;

    
    /* Enable non-correctable RAM ECC error reporting*/
    ECSM_init();
    
    printf("ECC error injection example\r\n");
    printf("\r\n");
    
    /**************************************************************************/
    /*                                                                        */
    /* Choose which error is supposed to be injected !                        */
    /*                                                                        */
    /**************************************************************************/
   
    #if 1
        Generate_noncorrectable_FLASH_ECC_error();
    #else
        Generate_noncorrectable_RAM_ECC_error();
    #endif
       

    /* Loop forever */
    for (;;) 
    {
        asm (nop);
    }
    
}


