/***********************************************************************
 * File: core_portme.c 
 *
 * Description: CoreMark porting layer functionality
 *
 ***********************************************************************
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * products. This software is supplied "AS IS" without any warranties.
 * NXP Semiconductors assumes no responsibility or liability for the
 * use of the software, conveys no license or title under any patent,
 * copyright, or mask work right to the product. NXP Semiconductors
 * reserves the right to make changes in the software without
 * notification. NXP Semiconductors also make no representation or
 * warranty that such application will be suitable for the specified
 * use without further testing or modification.
 **********************************************************************/



#include "coremark.h"
#include "core_portme.h"
#include "pin_mux.h"
#include "fsl_ctimer.h"
#include "fsl_usart.h"
#include "fsl_clock.h"
#include "fsl_debug_console.h"
#include "board.h"
#include "spifi_flash.h"

#if VALIDATION_RUN1999
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;

ee_u32 default_num_contexts = 1;

CORETIMETYPE barebones_clock(void);

#define GETMYTIME(_t) (*_t=barebones_clock())
#define MYTIMEDIFF(fin,ini) ((fin)-(ini))

static CORETIMETYPE start_time_val, stop_time_val;

// todo __align(16) uint32_t m0Stack[0x200]; // Stack must be aligned to 16 byte boundry)
//__align(16) uint32_t m0Stack[0x1000]; // Stack must be aligned to 16 byte boundry)
__attribute__((aligned(16))) uint32_t m0Stack[0x1000]; // Stack must be aligned to 16 byte boundry)

/**
 * Read and save benchmark start time
 *
 * This function will be called before starting the timed portion of the
 * benchmark.  It reads the current system tick value from the timer and
 * stores it in start_time_val.
 *
 */
void start_time(void) {
    GETMYTIME(&start_time_val);
}

/**
 * Read and save benchmark stop time
 *
 * This function will be called after ending the timed portion of the benchmark.
 * It reads the current system tick value from the timer and stores it in
 * stop_time_val.
 *
 */
void stop_time(void) {
    GETMYTIME(&stop_time_val);
}

/**
 * Return time difference in ticks between stop_time_val and start_time_val,
 * (see start_time() and stop_time() functions)
 *
 * @return Time difference in ticks between stop_time_val and 
 */
CORE_TICKS get_time(void) {
    CORE_TICKS elapsed = (CORE_TICKS) (MYTIMEDIFF(stop_time_val, start_time_val));
    return elapsed;
}

/**
 * Converts the input argument ticks into the equivalent time in seconds
 *
 * @param ticks  Tick value to convert to seconds
 * @return  Returns the equivalent time in seconds represented by ticks
 */
secs_ret time_in_secs(CORE_TICKS ticks) {

    secs_ret retval = ((secs_ret)ticks / 1000);
    return retval;
}

/**
 * Return current system timer value
 *
 * @return  Returns current system timer value, i.e., system ticks
 */
CORETIMETYPE barebones_clock() {

    return CTIMER_GetTimerCountValue(CTIMER3);

}

/**
 * Send a character to the system UART
 * 
 * @param c  Character to send
 */
void portable_send_char(char c) {

    USART_WriteBlocking(USART0, (const uint8_t *)&c, 1);
}

/**
 * Memory allocation routine
 *
 * PORTME:  This function provides a target specific memory allocation.  If 
 * available it is probably best to use the C library malloc() function.  If this
 * is the case ensure that there is a heap defined.  Also see portable_free()
 */
void *portable_malloc(size_t size) {

    return malloc(size);
}

/**
 * Free a block of memory
 * 
 * PORTME:  This function provides a target specific memory free.  If available
 * it is probably best to use the C library free() function.  Also see 
 * portable_malloc()
 * 
 * @param p  Pointer to block of memory to free
 */
void portable_free(void *p) {

    free(p);
}

//*************************************************************
//
//*************************************************************

/**
 * Initializes functionality specific to the chip/platform
 *
 * This function calls target specific functionality to initialize the system
 * in order to execute the benchmark.  It also does does various checks for 
 * portability errors.  Key functionality that must be initialized/powered up:
 *   System clocks
 *   UART for program output
 *   Timer to provide system time ticks
 *   Miscellaneous 
 * 
 * @param p     Not used
 * @param argc  Not used
 * @param argv  Not used
 */
#include "spifi_flash_test.h"
void portable_init(core_portable *p, int *argc, char *argv[]) {

    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");
    }


#if ((MULTITHREAD>1) && (MASTER==1) ) || (MULTITHREAD==1)

    BOARD_BootClockPLL220M();

    /* Debug uart initialize */
    CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0);  /* attach 12 MHz clock to FLEXCOMM0 (debug console) */
    BOARD_InitPins();
    BOARD_InitDebugConsole();
    ee_printf("init_UART() completed...\n");
    
    /* SPIFI flash initialize */
    spifi_flash_init();
    spifi_set_memory_mode();
    ee_printf("spifi_flash_init() completed...\n");

    /* Ctimer3 Initialize */
    ctimer_config_t config;

    SYSCON->ASYNCAPBCTRL = 1;               /* Enable the asynchronous bridge */
    
    CLOCK_AttachClk(kFRO12M_to_ASYNC_APB);  /* Use 12 MHz clock for some of the Ctimers */
    
    CTIMER_GetDefaultConfig(&config);
    config.prescale = 12000000/1000-1;
    config.mode = kCTIMER_TimerMode;

    CTIMER_Init(CTIMER3, &config);
    CTIMER_StartTimer(CTIMER3);
    ee_printf("init_timer() completed...\n");
    
    ee_printf("coremark code is running...\r\n");
    
#else
#endif

}
 

/**
 * Program exit routine
 * 
 * Routine called after test is completed. This function never exits.  
 * 
 * @param p  Not used
 */
void portable_fini(core_portable *p) {
    while (1) {
    }
}

/**
 * Routine called to report a runtime error
 * 
 * @param file
 * @param line
 */
void check_failed(uint8_t *file, uint32_t line) {

    /* Infinite loop */
    while (1)
        ;
}


/*
 * PORTME:  If doing multicore testing add functionality here.
 */
#if (MULTITHREAD>1)

/* Function: core_start_parallel
    Start benchmarking in a parallel context.
 */
ee_u8 core_start_parallel(core_results *res) {
    return (ee_u8) 0;
}

/* Function: core_stop_parallel
    Stop a parallel context execution of Coremark, and gather the results.
    
 */
ee_u8 core_stop_parallel(core_results *res) {
    return (ee_u8) 0;
}

#endif




