/***********************************************************************
*
*             Copyright 2011 Mentor Graphics Corporation
*                         All Rights Reserved.
*
* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS
* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS
* SUBJECT TO LICENSE TERMS.
*
************************************************************************

************************************************************************
*
*   FILE NAME
*
*       renesas_sh_rtl.c
*
*   DESCRIPTION
*
*       This file contains the Renesas SuperH run-time library functionality
*
*   FUNCTIONS
*
*       ESAL_TS_RTE_Initialize
*       ESAL_GE_RTE_Cxx_Region_Objects_Initialize
*       ESAL_TS_RTE_Cxx_System_Objects_Initialize
*       ESAL_TS_RTE_Cxx_Exceptions_Initilize
*       open
*       close
*       write
*       read
*       IO_Init
*       sbrk
*       abort
*
*   DEPENDENCIES
*
*       nucleus.h                  Contains system constants common to both the
*                                  application and the actual Nucleus PLUS components.
*       nu_kernel.h                Contains kernel constants common to both the
*                                  application and the actual Nucleus PLUS kernel.
*       stdio.h                    RTL I/O functions
*       stdlib.h                   RTL standard library functions
*       string.h                   RTL string functions
*       stddef.h                   RTL type definitions
*
***********************************************************************/

/* Include header file for ESAL layer definitions */
#include "nucleus.h"
#include "kernel/nu_kernel.h"

#if (ESAL_TS_RTL_SUPPORT == NU_TRUE)

/* Include RTL header file */
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h> 
#include    <stddef.h>

/* Defines for RTL low-level interface */
#define IOSTREAM    3       /* IO Stream */
#define STDIN       0       /* Standard input */
#define STDOUT      1       /* Standard output */
#define STDERR      2       /* Standard error output */
#define MINSTREAM   0       /* Minimum stream files */
#define MAXSTREAM   3       /* Maximum stream files */
#define O_RDONLY    0x0001  /* Read only flag */
#define O_WRONLY    0x0002  /* Write only flag */
#define O_RDWR      0x0004  /* Both read and write flag */
#define CR          0x0d    /* Carriage return */
#define LF          0x0a    /* Line feed */
#define BUFF_SIZE    1       /* stream buffer size */
#define HEAPSIZE    0x400   /* Area size managed by sbrk */

/* External variables used for RTL low-level interface */
extern const INT _nfiles;
extern struct _iobuf _iob[IOSTREAM];
extern UINT8 sml_buf[IOSTREAM];

#pragma pack 4
union _heap_area_union {
    UINT32   word32;             /* Word for 4-byte alignment */
    char     heap[HEAPSIZE];     /* Declaration of area managed by sbrk */
};

static union _heap_area_union heap_area;
#pragma unpack

char *brk = (char *)&heap_area; /* End address allocated by sbrk */
INT32 stream_mode[MAXSTREAM];  /* Open stream mode specification area */

/* Local function prototypes */
static VOID IO_Init(VOID);

#endif /* ESAL_TS_RTL_SUPPORT == NU_TRUE */

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_TS_RTE_Initialize
*
*   DESCRIPTION
*
*       This function initializes the run-time environment as required
*       for the given toolset
*
*   CALLED BY
*
*       ESAL_GE_RTE_Initialize
*
*   CALLS
*
*       IO_Init
*       setvbuf
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
VOID    ESAL_TS_RTE_Initialize(VOID)
{
#if (ESAL_TS_RTL_SUPPORT == NU_TRUE)

    /* Initialize I/O */
    IO_Init();

    /* Set I/O buffer area */
    setvbuf(stdin, NU_NULL, _IONBF, 0);
    setvbuf(stdout, NU_NULL, _IONBF, 0);
    setvbuf(stderr, NU_NULL, _IONBF, 0);

#endif /* ESAL_TS_RTL_SUPPORT == NU_TRUE */    
}

#if (ESAL_TS_RTL_SUPPORT == NU_TRUE)

/***********************************************************************
*
*   FUNCTION
*
*       open
*
*   DESCRIPTION
*
*       Low level function to open the stream.
*
*   CALLED BY
*
*       None
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       INT8 *stream                      - Stream to be used
*       INT16 mode                        - Stream mode
*       INT16 flag                        - Stream flag
*
*   OUTPUTS
*
*       INT32 ret                         - Return value
*
***********************************************************************/
INT32 open(INT8 *stream, INT16 mode, INT16 flag)
{
    INT32 ret = 0;

    /* Check mode of the stream */
    if (strcmp(stream, "stdin") == NU_NULL)
   {
        /* Standard input stream */
        if ((mode & O_RDONLY) == NU_NULL)
        {
            ret = -1;
        }

        if (ret == 0)
        {
            stream_mode[STDIN] = mode;
            ret = STDIN;
        }
    }
    else if (strcmp(stream,"stdout") == NU_NULL)
    {
        /* Standard output stream */
        if ((mode & O_WRONLY) == NU_NULL)
        {
            ret = -1;
        }

        if (ret == 0)
        {
            stream_mode[STDOUT] = mode;
            ret = STDOUT;
        }
    }
    else if (strcmp(stream,"stderr") == NU_NULL)
    {
        /* Standard error stream */
        if ((mode & O_WRONLY) == NU_NULL)
        {
            ret = -1;
        }

        if (ret == 0)
        {
            stream_mode[STDERR] = mode;
            ret = STDERR;
        }
    }
    else
    {
        /* Error */
        ret = -1;                        
    }

    /* Suppressing harmless warnings */
    NU_UNUSED_PARAM(flag);

    return (ret);
}

/***********************************************************************
*
*   FUNCTION
*
*       close
*
*   DESCRIPTION
*
*       Low level function to close the stream.
*
*   CALLED BY
*
*       None
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       INT16 stream_number               - Stream number
*
*   OUTPUTS
*
*                                         - Always return 0
*
***********************************************************************/
INT32 close(INT16 stream_number)
{
    INT32 ret = 0;

    /* Check stream range */
    if((stream_number < MINSTREAM) || (MAXSTREAM < stream_number))
    {
        ret = -1;
    }

    if (ret == 0)
    {
        /* Reset stream mode */
       stream_mode[stream_number] = 0;
    }

    return (0);
}

/***********************************************************************
*
*   FUNCTION
*
*       write
*
*   DESCRIPTION
*
*       Low level function to redirect IO to serial.
*
*   CALLED BY
*
*       None
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       INT file                          - Unused
*       CHAR *ptr                         - String to output
*       INT len                           - Length of the string
*
*   OUTPUTS
*
*       INT status                        - Number of characters transmitted
*                                         - 1 for error 
*
***********************************************************************/
INT write (INT file, char *ptr, INT len)
{
    INT i;
    INT status;

    /* Check for NU_NULL pointer */
    if (ESAL_GE_RTE_Byte_Write != NU_NULL)
    {
        /* Loop until we transmit the required number of characters */
        for (i = 0; i < len; i++)
        {
            /* Transmit one character */
            (*ESAL_GE_RTE_Byte_Write)(*ptr++);
        }
    
        /* Return the number of characters transmitted */
        status = len;
    }
    else
    {
        /* Return error */
        status = -1;
    }

    /* Suppressing harmless warnings */
    NU_UNUSED_PARAM(file);

    return (status);
}

/***********************************************************************
*
*   FUNCTION
*
*       read
*
*   DESCRIPTION
*
*       Low level function to redirect IO to serial.
*
*   CALLED BY
*
*       None
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       INT file                          - Unused
*       CHAR *ptr                         - String
*       INT len                           - Unused
*
*   OUTPUTS
*
*       INT status                        - Number of characters received
*                                         - 1 for error 
*
***********************************************************************/
INT read (INT file, char *ptr, INT len)
{
    INT i;
    INT c;
    INT status;
    
    /* Check for NU_NULL pointer */
    if (ESAL_GE_RTE_Byte_Read != NU_NULL)
    {
        /* Loop until we recieve the required number of characters */
        for (i = 0; i < len; i++)
        {
            /* Try and receive one character */
            while ((c = (*ESAL_GE_RTE_Byte_Read)()) == -1)
            {
                /* Loop until we receive a character */
            }
            
            /* Store the received character in the buffer */
            *ptr++ = c;
           }
    
        /* Return the number of characters received */
        status = len;
    }
    else
    {
        /* Return error */
        status = -1;
    }

    /* Suppressing harmless warnings */
    NU_UNUSED_PARAM(file);

    return (status);
}

/***********************************************************************
*
*   FUNCTION
*
*       IO_Init
*
*   DESCRIPTION
*
*       Low level function to initialize IO library.
*
*   CALLED BY
*
*       None
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
static VOID IO_Init(VOID)
{
    FILE   *fp;

    /* Initial settings of file data types */
    for (fp = _iob; fp < (_iob + _nfiles); fp++)
    {
        fp->_bufptr = NU_NULL;
        fp->_bufcnt = 0;
        fp->_buflen = 0;
        fp->_bufbase = NU_NULL;
        fp->_ioflag1 = 0;
        fp->_ioflag2 = 0;
        fp->_iofd = 0;
    }

    /* Open standard input file */
    if (freopen("stdin", "r", stdin) == NU_NULL)
    {
        stdin->_ioflag1 = 0xff;
    }

    /* Disable data buffering */
    stdin->_ioflag1 |= _IOUNBUF;

    /* Open standard output file */
    if (freopen("stdout", "w", stdout) == NU_NULL)
    {
        stdout->_ioflag1 = 0xff;
    }

    /* Disable data buffering */
    stdout->_ioflag1 |= _IOUNBUF;

    /* Open standard error file */
    if (freopen("stderr", "w", stderr) == NU_NULL)
    {
        stderr->_ioflag1 = 0xff;
    }

    /* Disable data buffering */
    stderr->_ioflag1 |= _IOUNBUF;
}

/***********************************************************************
*
*   FUNCTION
*
*       sbrk
*
*   DESCRIPTION
*
*       Low level function to calculate the end of heap
*
*   CALLED BY
*
*       None
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       size_t      size                  - Heap size
*
*   OUTPUTS
*
*       char *heap_end                    - End of heap pointer
*
***********************************************************************/
char* sbrk(size_t size)
{
    char *heap_end;

    /* Empty area size */
    if((brk + size) > (heap_area.heap + HEAPSIZE))
    {     

        heap_end = (char *)-1;
    }
    else 
    {
        /* Area assignment */
        heap_end = brk;

        /* End address update */
        brk += size;
    }

    return (heap_end);
}

/***********************************************************************
*
*   FUNCTION
*
*       abort
*
*   DESCRIPTION
*
*       Low level function for abnormal termination
*
*   CALLED BY
*
*       None
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
void abort(void)
{
    while (1);
}

#endif /* ESAL_TS_RTL_SUPPORT == NU_TRUE */

#if (defined(CFG_NU_OS_SVCS_CXX_ENABLE))

#if (CFG_NU_OS_SVCS_CXX_INIT_STATIC_OBJECTS == NU_TRUE)

/*************************************************************************
*
*   FUNCTION
*
*       ESAL_TS_RTE_Cxx_Region_Objects_Initialize
*
*   DESCRIPTION
*
*       Initialize C++ Static Objects in a specific memory region.
*
*   CALLED BY
*
*       ESAL_TS_RTE_Cxx_System_Objects_Initialize
*
*   CALLS
*
*       None 
*
*   INPUTS
*
*       region_start   - Starting address of memory region to call
*                        constructors.
*
*       region_end     - Ending address of memory region to call constructors.
*
*   OUTPUTS
*
*       None
*
*************************************************************************/
VOID ESAL_TS_RTE_Cxx_Region_Objects_Initialize(VOID *   region_start,
                                               VOID *   region_end)
{
    /* Suppressing harmless warnings */
    NU_UNUSED_PARAM(region_start);
    NU_UNUSED_PARAM(region_end);
}

/*************************************************************************
*
*   FUNCTION
*
*       ESAL_TS_RTE_Cxx_System_Objects_Initialize
*
*   DESCRIPTION
*
*       Initialize C++ System Objects.
*
*   CALLED BY
*
*       CXX_RTE_Initialize
*
*   CALLS
*
*       _CALL_INIT
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
*************************************************************************/
VOID ESAL_TS_RTE_Cxx_System_Objects_Initialize(VOID)
{
    /* Call toolset specific function C++ related initialization. */
    _CALL_INIT();
}

#endif /* (CFG_NU_OS_SVCS_CXX_INIT_STATIC_OBJECTS == NU_TRUE) */

#if (CFG_NU_OS_SVCS_CXX_INIT_EXCEPTION_SUPPORT == NU_TRUE)

/*************************************************************************
*
*   FUNCTION
*
*       ESAL_TS_RTE_Cxx_Exceptions_Initialize
*
*   DESCRIPTION
*
*       Initialize C++ Exceptions.
*
*   CALLED BY
*
*       CXX_RTE_Initialize
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
*************************************************************************/
VOID ESAL_TS_RTE_Cxx_Exceptions_Initialize(VOID)
{
    /* Nothing to do here. */

    return;
}

#endif /* (CFG_NU_OS_SVCS_CXX_INIT_EXCEPTION_SUPPORT == NU_TRUE) */

#endif /* CFG_NU_OS_SVCS_CXX_ENABLE */
