/*
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"


/*******************************************************************************
 * Definitions
 ******************************************************************************/
/* Address of RAM, where the image for core1 should be copied */
#define CORE1_BOOT_ADDRESS (void *)0x04000000

#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
extern uint32_t Image$$CORE1_REGION$$Base;
extern uint32_t Image$$CORE1_REGION$$Length;
#define CORE1_IMAGE_START &Image$$CORE1_REGION$$Base
#elif defined(__ICCARM__)
extern unsigned char core1_image_start[];
#define CORE1_IMAGE_START core1_image_start
#elif defined(__GNUC__)
extern const char m0_image_start[];
extern const char *m0_image_end;
extern int m0_image_size;
#define CORE1_IMAGE_START ((void *)m0_image_start)
#define CORE1_IMAGE_SIZE ((void *)m0_image_size)
#endif

//#ifdef __CC_ARM
//volatile int core1_coremark      __attribute__((section(".ARM.__at_0x20041004")));
//volatile int core1_costtime      __attribute__((section(".ARM.__at_0x20041008")));
//volatile int core1_finish_flag   __attribute__((section(".ARM.__at_0x2004100c")));
//volatile int core1_powerquadmark __attribute__((section(".ARM.__at_0x20041020")));

volatile int core1_coremark      __attribute__((section(".ARM.__at_0x20038000")));
volatile int core1_costtime      __attribute__((section(".ARM.__at_0x20038010")));
volatile int core1_finish_flag   __attribute__((section(".ARM.__at_0x20038020")));
volatile int core1_powerquadmark __attribute__((section(".ARM.__at_0x20038030")));

volatile float core0_coremark = 0.0f;
volatile float core0_costtime = 0.0f;
volatile int   core0_powerquadmark = 0;

extern volatile uint32_t gTaskPowerQuadCounter;
extern volatile bool gCoreMarkDone;

//#elif __ICCARM__
//__no_init char var@0x20000000;
//#endif

static MAILBOX_Type Mailbox_temp;


/*******************************************************************************
 * Prototypes
 ******************************************************************************/

#ifdef CORE1_IMAGE_COPY_TO_RAM
uint32_t get_core1_image_size(void);
#endif

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


/*******************************************************************************
 * Code
 ******************************************************************************/

#ifdef CORE1_IMAGE_COPY_TO_RAM
uint32_t get_core1_image_size(void)
{
    uint32_t core1_image_size;
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
    core1_image_size = (uint32_t)&Image$$CORE1_REGION$$Length;
#elif defined(__ICCARM__)
#pragma section = "__sec_core"
    core1_image_size = (uint32_t)__section_end("__sec_core") - (uint32_t)&core1_image_start;
#elif defined(__GNUC__)
    core1_image_size = (uint32_t)m0_image_size;
#endif
    return core1_image_size;
}
#endif


/* 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;

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

#if RUN_IN_RAMX
    ee_printf("CORE0_System Running on RAM-X\n");
#endif
#if RUN_IN_FLASH
    ee_printf("CORE0_System Running on RAM0\n");
    ee_printf("CORE1_System Running on RAM-X\n");
#endif
// while(1);


    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;
    // core1_finish_flag = 0;



    Task_PowerQuad_Start();

}

/* Function : portable_fini
	Target specific final code
*/
#if (defined(__ICCARM__))
//__ramfunc
#endif
void portable_fini(core_portable *p)
{
    p->portable_id=0;
    core0_powerquadmark = gTaskPowerQuadCounter;
    Task_PowerQuad_EndHook();
    ee_printf("DONE\r\n");
    ee_printf("\r\n\r\n");
#if 0
    ee_printf("********** RESULT **********\r\n");
    ee_printf("core 0:\r\n");
    ee_printf("core0_coremark     : %f\r\n", core0_coremark);
    ee_printf("core0_costtime     : %f\r\n", core0_costtime);
    ee_printf("core0_powerquadmark: %d\r\n", core0_powerquadmark);
#endif
    while (core1_finish_flag == 0);
#if 0
    ee_printf("core 1:\r\n");
    ee_printf("core1_coremark     : %d\r\n", core1_coremark);
    ee_printf("core1_costtime     : %d\r\n", core1_costtime);
    //ee_printf("core1_powerquadmark: %d\r\n", core1_powerquadmark);
    ee_printf("*********** DONE ***********\r\n");
#endif
    // Task_PowerQuad_EndHook();
    //while(1) {
    //    __WFI();
    //}

    gCoreMarkDone =  true;
}

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

