/*
Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Original Author: Shay Gal-on
LPC5500 Porting file Author : nxp58695
*/

#include <stdio.h>
#include <stdlib.h>
#include "coremark.h"

/* added for LPC5500 platform */
#include "board.h"
#include "fsl_usart.h"
#include "fsl_power.h"
#include "pin_mux.h"
#include "core_cm33.h"
#include <stdbool.h>
#include "mcmgr.h"

//0x2003'214c
//volatile int core1_coremark1     __attribute__((section(".ARM.__at_0x20041004")));
//volatile int core1_costtime1     __attribute__((section(".ARM.__at_0x20041008")));
//volatile int core1_finish_flag1  __attribute__((section(".ARM.__at_0x2004100C")));
//volatile int core1_powerquadmark __attribute__((section(".ARM.__at_0x20041020")));

volatile int core1_coremark1     __attribute__((section(".ARM.__at_0x20038000")));
volatile int core1_costtime1     __attribute__((section(".ARM.__at_0x20038010")));
volatile int core1_finish_flag1  __attribute__((section(".ARM.__at_0x20038020")));
volatile int core1_powerquadmark __attribute__((section(".ARM.__at_0x20038030")));

extern int CORE1_Coremark_score=0;
extern int CORE1_time_cost=0;

extern volatile uint32_t gTaskPowerQuadCounter;

/* User should consider ITERATIONS values */
//#define ITERATIONS 4000
#define ITERATIONS 8000

#define RESULT_OUTPUT 1

#if VALIDATION_RUN
  volatile ee_s32 seed1_volatile=0x3415;
  volatile ee_s32 seed2_volatile=0x3415;
  volatile ee_s32 seed3_volatile=0x66;
#endif
#if PERFORMANCE_RUN
  volatile ee_s32 seed1_volatile=0x0;
  volatile ee_s32 seed2_volatile=0x0;
  volatile ee_s32 seed3_volatile=0x66;
#endif
#if PROFILE_RUN
  volatile ee_s32 seed1_volatile=0x8;
  volatile ee_s32 seed2_volatile=0x8;
  volatile ee_s32 seed3_volatile=0x8;
#endif
  volatile ee_s32 seed4_volatile=ITERATIONS;
  volatile ee_s32 seed5_volatile=0;

/* Porting : Timing functions
   How to capture time and convert to seconds must be ported to whatever is supported by the platform.
   e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc.
   Sample implementation for standard time.h and windows.h definitions included.
*/
/* Define : TIMER_RES_DIVIDER
   Divider to trade off timer resolution and total time that can be measured.

   Use lower values to increase resolution, but make sure that overflow does not occur.
   If there are issues with the return value overflowing, increase this value.
*/
#define EE_TICKS_PER_SEC 1000
volatile uint32_t gTicks; /* Systick counter var. */
#define SysTick_Counter_Disable   ((uint32_t)0xFFFFFFFE)
#define SysTick_Counter_Enable    ((uint32_t)0x00000001)
#define SysTick_Counter_Clear     ((uint32_t)0x00000000)

/* Function : start_time
   This function will be called right before starting the timed portion of the benchmark.

   Implementation may be capturing a system timer (as implemented in the example code)
   or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0.
*/
void start_time(void) {
#if RESULT_OUTPUT
    gTicks = 0;
    /* Enable SystemTick every 1mS */
    SysTick_Config(SystemCoreClock/1000);
#endif
}

/* Function : stop_time
   This function will be called right after ending the timed portion of the benchmark.

   Implementation may be capturing a system timer (as implemented in the example code)
   or other system parameters - e.g. reading the current value of cpu cycles counter.
*/
void stop_time(void) {
#if RESULT_OUTPUT
    SysTick->CTRL &= SysTick_Counter_Disable; /* Stop the Timer and get the encoding time */
    SysTick->VAL   = SysTick_Counter_Clear; /* Clear the SysTick Counter */
#endif
}
/* Function : get_time
   Return an abstract "ticks" number that signifies time on the system.

   Actual value returned may be cpu cycles, milliseconds or any other value,
   as long as it can be converted to seconds by <time_in_secs>.
   This methodology is taken to accomodate any hardware or simulated platform.
   The sample implementation returns millisecs by default,
   and the resolution is controlled by <TIMER_RES_DIVIDER>
*/
CORE_TICKS get_time(void) {
    CORE_TICKS elapsed = (CORE_TICKS)gTicks;
    return elapsed;
}
/* Function : time_in_secs
   Convert the value returned by get_time to seconds.

   The <secs_ret> type is used to accomodate systems with no support for floating point.
   Default implementation implemented by the EE_TICKS_PER_SEC macro above.
*/
secs_ret time_in_secs(CORE_TICKS ticks) {
    secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC;
    return retval;
}

ee_u32 default_num_contexts=1;

/*!
 * @brief Function to create delay for Led blink.
 */
void delay(void)
{
    volatile uint32_t i = 0;
    for (i = 0; i < 1000000; ++i)
    {
        __asm("NOP"); /* delay */
    }
}

extern void Task_PowerQuad_Start(void);
extern void Task_PowerQuad_EndHook(void);

/* Function : portable_init
   Target specific initialization code
   Test for some common mistakes.
*/
void portable_init(core_portable *p, int *argc, char *argv[])
{

    uint32_t startupData, i;
    mcmgr_status_t status;
      /* Initialize MCMGR, install generic event handlers */
    MCMGR_Init();

    /* Get the startup data */
    do
    {
        status = MCMGR_GetStartupData(&startupData);
    } while (status != kStatus_MCMGR_Success);

    /* Make a noticable delay after the reset */
    /* Use startup parameter from the master core... */
    for (i = 0; i < startupData; i++)
        delay();


    /* added intialize function here for LPC5500 */
#ifdef COREMARK_SCORE_TEST
    usart_config_t config;
#endif

    /* Set Main Freq as 12Mhz */
    BOARD_BootClockFRO12M();

#ifdef RUN_IN_12MHZ
    /* Don't alter lower bits */
    /* Adjust FMC waiting time cycles */
    SYSCON->FMCCR = (SYSCON->FMCCR & 0xFFFF0FFF) | (0x00 << 12); /* Flash accesses use 1 CPU clocks */
    /* Set Main Freq as 12Mhz */
    BOARD_BootClockFRO12M();
#ifndef COREMARK_SCORE_TEST
    /* Set up DCDC voltage */
    PMC->DCDC0 = (PMC->DCDC0 & (~PMC_DCDC0_VOUT_MASK)) | PMC_DCDC0_VOUT(V_DCDC_0P950);
#endif
#endif

#ifdef RUN_IN_48MHZ
    /* Don't alter lower bits */
    /* Adjust FMC waiting time cycles */
    SYSCON->FMCCR = (SYSCON->FMCCR & 0xFFFF0FFF) | (0x03 << 12); /* Flash accesses use 4 CPU clocks */
    /* Set Main Freq as 48Mhz */
    BOARD_BootClockFROHF48M();
#ifndef COREMARK_SCORE_TEST
    /* Set up DCDC voltage */
    PMC->DCDC0 = (PMC->DCDC0 & (~PMC_DCDC0_VOUT_MASK)) | PMC_DCDC0_VOUT(V_DCDC_0P950);
#endif
#endif

#ifdef RUN_IN_96MHZ
    /* Don't alter lower bits */
    /* Adjust FMC waiting time cycles */
    SYSCON->FMCCR = (SYSCON->FMCCR & 0xFFFF0FFF) | (0x06 << 12); /* Flash accesses use 7 CPU clocks */
    /* Set Main Freq as 96Mhz */
//    BOARD_BootClockFROHF96M();
    
    //    BOARD_BootClockFROHF96M();
    BOARD_BootClockPLL150M();
#ifndef COREMARK_SCORE_TEST
    /* Set up DCDC voltage */
    PMC->DCDC0 = (PMC->DCDC0 & (~PMC_DCDC0_VOUT_MASK)) | PMC_DCDC0_VOUT(V_DCDC_1P000);
#endif
#endif

    /* Update System Frequency Value */
    SystemCoreClockUpdate();
    /* Board pin init */
//    BOARD_InitPins();
    BOARD_InitPins_Core1();

#ifdef COREMARK_SCORE_TEST
    /* attach 12 MHz clock to FLEXCOMM0 (debug console) */
    CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
    BOARD_InitDebugConsole();
    /*
     * config.baudRate_Bps = 115200U;
     * config.parityMode = kUSART_ParityDisabled;
     * config.stopBitCount = kUSART_OneStopBit;
     * config.loopback = false;
     * config.enableTx = false;
     * config.enableRx = false;
     */
    USART_GetDefaultConfig(&config);
    config.baudRate_Bps = 115200;
    config.enableTx = true;
    config.enableRx = true;
    USART_Init(USART0, &config, 12000000);
#endif

    /* Print main clock frequency information */
    ee_printf("CORE1_SystemCoreClock: %d\n", SystemCoreClock);
#if RUN_IN_RAMX
    ee_printf("CORE1_System Running on RAM-X\n");
#endif
#if RUN_IN_FLASH
    ee_printf("core1 move flash to RAM3-4 and run.\n");
#endif

#ifndef COREMARK_SCORE_TEST
    /* Enable Automatic Clock Gating for all modules */
    SYSCON->AUTOCLKGATEOVERRIDE = 0xC0DE0000;
    /* Enable clocks only for : ROM, all SRAM_CTRL, Flexcomm0 and Analog Controller. All others modules clocks are disabled */
#ifdef RUN_IN_RAMX
    SYSCON->AHBCLKCTRLX[0] = 0x000001FB;    /* SRAM_CTRL1,2,3,4,FMC  */
    SYSCON->AHBCLKCTRLX[1] = 0x00000000;    /* Flexcomm 0 */
    SYSCON->AHBCLKCTRLX[2] = 0x00000000;    /* Analog Controller */
#endif
#ifdef RUN_IN_FLASH
    SYSCON->AHBCLKCTRLX[0] = 0x000001FB;    /* SRAM_CTRL1,2,3,4, FMC  */
    SYSCON->AHBCLKCTRLX[1] = 0x00000000;    /* Flexcomm 0 */
    SYSCON->AHBCLKCTRLX[2] = 0x00000000;    /* Analog Controller */
#endif

  /*
   * Power down all modules not required
   */
  PMC->PDRUNCFGSET0 =   //PMC_PDRUNCFG0_PDEN_DCDC_MASK          |
                        //PMC_PDRUNCFG0_PDEN_BIAS_MASK          |
                        PMC_PDRUNCFG0_PDEN_BODCORE_MASK         |
                        PMC_PDRUNCFG0_PDEN_BODVBAT_MASK         |
                        //PMC_PDRUNCFG0_PDEN_FRO192M_MASK       |
                        PMC_PDRUNCFG0_PDEN_FRO32K_MASK          |
                        PMC_PDRUNCFG0_PDEN_XTAL32K_MASK         |
                        PMC_PDRUNCFG0_PDEN_XTAL32M_MASK         |
                        PMC_PDRUNCFG0_PDEN_PLL0_MASK            |
                        PMC_PDRUNCFG0_PDEN_PLL1_MASK            |
                        PMC_PDRUNCFG0_PDEN_USBFSPHY_MASK        |
                        PMC_PDRUNCFG0_PDEN_USBHSPHY_MASK        |
                        PMC_PDRUNCFG0_PDEN_COMP_MASK            |
                        //PMC_PDRUNCFG0_PDEN_LDOMEM_MASK        |
                        PMC_PDRUNCFG0_PDEN_LDODEEPSLEEP_MASK    |
                        PMC_PDRUNCFG0_PDEN_LDOUSBHS_MASK        |
                        PMC_PDRUNCFG0_PDEN_AUXBIAS_MASK         |
                        PMC_PDRUNCFG0_PDEN_LDOXO32M_MASK        |
                        //PMC_PDRUNCFG0_PDEN_LDOFLASHNV_MASK    |
                        PMC_PDRUNCFG0_PDEN_RNG_MASK             |
                        PMC_PDRUNCFG0_PDEN_PLL0_SSCG_MASK;
#endif

    if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) {
        ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n");
    }
    if (sizeof(ee_u32) != 4) {
        ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n");
    }
    p->portable_id=1;

//#if RUN_IN_RAMX
//    /* Re-allicate interrput VTOR table to SRAM-0 */
//    memcpy((uint32_t*)0x20000000, (uint32_t*)SCB->VTOR, 0x140);
//    SCB->VTOR = (uint32_t)0x20000000;
//    /* Power Down the Flash */
//    //FLASH->CMD = 0x1;
//#endif

    Task_PowerQuad_Start(); /* start the PowerQuad benchmark task. */
}

/* Function : portable_fini
	Target specific final code
*/
#if (defined(__ICCARM__))
//__ramfunc
#endif
void portable_fini(core_portable *p)
{
    Task_PowerQuad_EndHook();
    core1_powerquadmark = gTaskPowerQuadCounter;
    //ee_printf("DONE\r\n");
    p->portable_id=0;
    core1_coremark1 = CORE1_Coremark_score;
    core1_costtime1 = CORE1_time_cost;
    core1_finish_flag1 = 1;

//    ee_printf("core1_coremark1: %d\n", core1_coremark1);
//    ee_printf("core1_costtime1: %d\n", core1_costtime1);
//    ee_printf("core1_finish_flag1: %d\n", core1_finish_flag1);

    //Task_PowerQuad_EndHook(); /* summarize the record of PowerQuad benchmark. */

    while(1) {
//        __WFI();
    }
}

/* Systick ISR. */
#if (defined(__ICCARM__))
//__ramfunc
#endif
void SysTick_Handler(void)
{
    gTicks++;
}

