/* ========================================================================== */
/*                                                                            */
/*                                                                            */
/*  NAME                                                                      */
/*     alg_malloc.c                                                           */
/*                                                                            */
/*  DESCRIPTION                                                               */
/*    This module implements an algorithm memory management "policy" in which */
/*  no memory is shared among algorithm objects.  Memory is, however          */
/*  reclaimed when objects are deleted.                                       */
/*                                                                            */
/*  preemption      sharing             object deletion                       */
/*  ----------      -------             ---------------                       */
/*  yes(*)          none                yes                                   */
/*                                                                            */
/*  Note 1: this module uses run-time support functions malloc() and free()   */
/*  to allocate and free memory.  Since these functions are *not* reentrant,  */
/*  either all object creation and deletion must be performed by a single     */
/*  thread or reentrant versions of these functions must be created.          */
/*                                                                            */
/*                                                                            */
/*   Copyright (c) 2001-2003 Texas Instruments Incorporated.                  
 * 
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the   
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "common/siuloc.h"

#include <ti/bios/include/std.h> /* Take from Bios*/
#include <ti/xdais/ialg.h>
#include <stdio.h>
#include <stdlib.h>     /* malloc/free declarations */
#include <string.h>     /* memset declaration */

#define INTERNAL_DATA_MEM_SIZE    (0x45D00)  // Need: 0x81C34
#define INTERNAL_PERSIST_MEM_SIZE (0x02500)
#define INTERNAL_SCRATCH_MEM_SIZE (0x43800)

/* list of some parameters macros for worst case memory allocation in external memory */
#define EXTERNAL_DATA_MEM_SIZE    (16*1920*1088)  //Need: 0xA7F520
#pragma DATA_SECTION( ExternalGlobalMemCore0, ".testCodecExtMemCore0");
#pragma DATA_SECTION( ExternalGlobalMemCore1, ".testCodecExtMemCore1");
#pragma DATA_SECTION( ExternalGlobalMemCore2, ".testCodecExtMemCore2");
#pragma DATA_SECTION( ExternalGlobalMemCore3, ".testCodecExtMemCore3");
#pragma DATA_SECTION( ExternalGlobalMemCore4, ".testCodecExtMemCore4");
#pragma DATA_SECTION( ExternalGlobalMemCore5, ".testCodecExtMemCore5");
#pragma DATA_SECTION( ExternalGlobalMemCore6, ".testCodecExtMemCore6");
#pragma DATA_SECTION( ExternalGlobalMemCore7, ".testCodecExtMemCore7");
//#pragma DATA_SECTION( internalDataMemory, ".testCodecIntMem");
//#pragma DATA_SECTION( pInternalDataMemory, ".testCodecIntMemInit");
//#pragma DATA_SECTION( internalDataMemorySize, ".testCodecIntMemInit");
#pragma DATA_SECTION( internalPersistMemory, ".testCodecIntMem");
#pragma DATA_SECTION( pInternalPersistMemory, ".testCodecIntMemInit");
#pragma DATA_SECTION( internalPersistMemorySize, ".testCodecIntMemInit");
#pragma DATA_SECTION( internalScratchMemory, ".testCodecIntMem");
#pragma DATA_SECTION( pInternalScratchMemory, ".testCodecIntMemInit");
#pragma DATA_SECTION( internalScratchMemorySize, ".testCodecIntMemInit");

unsigned char ExternalGlobalMemCore0[EXTERNAL_DATA_MEM_SIZE];
unsigned char *ExternalGlobalMemPool = ExternalGlobalMemCore0;
unsigned int externalDataMemorySize = EXTERNAL_DATA_MEM_SIZE;
unsigned char ExternalGlobalMemCore1[EXTERNAL_DATA_MEM_SIZE];
unsigned char ExternalGlobalMemCore2[EXTERNAL_DATA_MEM_SIZE];
unsigned char ExternalGlobalMemCore3[EXTERNAL_DATA_MEM_SIZE];
unsigned char ExternalGlobalMemCore4[EXTERNAL_DATA_MEM_SIZE];
unsigned char ExternalGlobalMemCore5[EXTERNAL_DATA_MEM_SIZE];
unsigned char ExternalGlobalMemCore6[EXTERNAL_DATA_MEM_SIZE];
unsigned char ExternalGlobalMemCore7[EXTERNAL_DATA_MEM_SIZE];
//unsigned char internalDataMemory[ INTERNAL_DATA_MEM_SIZE];
//unsigned char *pInternalDataMemory = internalDataMemory;
//unsigned int  internalDataMemorySize = INTERNAL_DATA_MEM_SIZE;
unsigned char internalPersistMemory[INTERNAL_PERSIST_MEM_SIZE];
unsigned char *pInternalPersistMemory = internalPersistMemory;
unsigned int internalPersistMemorySize = INTERNAL_PERSIST_MEM_SIZE;
unsigned char internalScratchMemory[INTERNAL_SCRATCH_MEM_SIZE];
unsigned char *pInternalScratchMemory = internalScratchMemory;
unsigned int internalScratchMemorySize = INTERNAL_SCRATCH_MEM_SIZE;

extern int errorNumber;

Bool
_ALG_allocMemory(IALG_MemRec memTab[], Int n);
Void
_ALG_freeMemory(IALG_MemRec memTab[], Int n);

void *
memAlignVc(size_t alignment, size_t size)
{
  return malloc(size);
} /* memAlignVc */

int
allocateMemTabRequest(IALG_MemRec *memTab)
{
  if (memTab->space == IALG_EXTERNAL)
    {
      unsigned int alignBytes;
      alignBytes = (((unsigned int) ExternalGlobalMemPool
          + (memTab->alignment - 1)) & (~(memTab->alignment - 1)));
      alignBytes -= (unsigned int) ExternalGlobalMemPool;
      ExternalGlobalMemPool += alignBytes;
      externalDataMemorySize -= alignBytes;
      if (externalDataMemorySize >= memTab->size)
        {
          /* allocate memory */
          memTab->base = ExternalGlobalMemPool;
          ExternalGlobalMemPool += memTab->size;
          externalDataMemorySize -= memTab->size;
        }
      else
        {
          memTab->base = 0;
        }
    }
  else
    {
      /* internal memory request */
      unsigned int alignBytes;

#if 0
      alignBytes = (((unsigned int) pInternalDataMemory + (memTab->alignment - 1)) & (~ (memTab->alignment - 1)));
      if(alignBytes!=0)
        {
          alignBytes -= (unsigned int) pInternalDataMemory;
          pInternalDataMemory += alignBytes;
          internalDataMemorySize -= alignBytes;
        }
      if(internalDataMemorySize >= memTab->size)
        {
          /* allocate memory */
          memTab->base = pInternalDataMemory;
          pInternalDataMemory += memTab->size;
          internalDataMemorySize -= memTab->size;
        }
      else
        {
          memTab->base = 0;
        }
#endif
      switch (memTab->attrs)
        {
      case IALG_SCRATCH:
        alignBytes = (((unsigned int) pInternalScratchMemory
            + (memTab->alignment - 1)) & (~(memTab->alignment - 1)));
        if (alignBytes != 0)
          {
            alignBytes -= (unsigned int) pInternalScratchMemory;
            pInternalScratchMemory += alignBytes;
            internalScratchMemorySize -= alignBytes;
          }
        if (internalScratchMemorySize >= memTab->size)
          {
            /* allocate memory */
            memTab->base = pInternalScratchMemory;
            pInternalScratchMemory += memTab->size;
            internalScratchMemorySize -= memTab->size;
          }
        else
          {
            memTab->base = 0;
          }
        break;
      case IALG_PERSIST:
      case IALG_WRITEONCE:
        alignBytes = (((unsigned int) pInternalPersistMemory
            + (memTab->alignment - 1)) & (~(memTab->alignment - 1)));
        if (alignBytes != 0)
          {
            alignBytes -= (unsigned int) pInternalPersistMemory;
            pInternalPersistMemory += alignBytes;
            internalPersistMemorySize -= alignBytes;
          }
        if (internalPersistMemorySize >= memTab->size)
          {
            /* allocate memory */
            memTab->base = pInternalPersistMemory;
            pInternalPersistMemory += memTab->size;
            internalPersistMemorySize -= memTab->size;
          }
        else
          {
            memTab->base = 0;
          }
        break;
      default:
        memTab->base = 0;
        }
    }
  return 0;
} /* allocateMemTabRequest */

int
freeMemTabRequest(IALG_MemRec *memTab)
{
  if (memTab->space == IALG_EXTERNAL)
    {
      memTab->base = 0;

      switch (siuContext.coreId)
        {
      case 0:
        ExternalGlobalMemPool = ExternalGlobalMemCore0;
        break;
      default:
        ExternalGlobalMemPool = ExternalGlobalMemCore1;
        break;
      case 2:
        ExternalGlobalMemPool = ExternalGlobalMemCore2;
        break;
      case 3:
        ExternalGlobalMemPool = ExternalGlobalMemCore3;
        break;
      case 4:
        ExternalGlobalMemPool = ExternalGlobalMemCore4;
        break;
      case 5:
        ExternalGlobalMemPool = ExternalGlobalMemCore5;
        break;
      case 6:
        ExternalGlobalMemPool = ExternalGlobalMemCore6;
        break;
      case 7:
        ExternalGlobalMemPool = ExternalGlobalMemCore7;
        break;
        }

      externalDataMemorySize = EXTERNAL_DATA_MEM_SIZE;

    }
  else
    {
      /* internal memory  free request. XXX see the code  below
       * for the dangers of calling them as normal mallocs. Free is faked!!!  */
      memTab->base = 0;
      pInternalPersistMemory = internalPersistMemory;
      internalPersistMemorySize = INTERNAL_PERSIST_MEM_SIZE;
    }
  return 0;
} /* freeMemTabRequest */

/*
 *  ======== ALG_exit ========
 */
Void
ALG_exit( Void)
{
}

/*
 *  ======== ALG_init ========
 */
Void
ALG_init( Void)
{
}

/*
 *  ======== _ALG_allocMemory ========
 */
Bool
_ALG_allocMemory(IALG_MemRec memTab[], Int n)
{
  Int i;

  switch (siuContext.coreId)
    {
  case 0:
    ExternalGlobalMemPool = ExternalGlobalMemCore0;
    break;
  case 1:
    ExternalGlobalMemPool = ExternalGlobalMemCore1;
    break;
  case 2:
    ExternalGlobalMemPool = ExternalGlobalMemCore2;
    break;
  case 3:
    ExternalGlobalMemPool = ExternalGlobalMemCore3;
    break;
  case 4:
    ExternalGlobalMemPool = ExternalGlobalMemCore4;
    break;
  case 5:
    ExternalGlobalMemPool = ExternalGlobalMemCore5;
    break;
  case 6:
    ExternalGlobalMemPool = ExternalGlobalMemCore6;
    break;
  case 7:
    ExternalGlobalMemPool = ExternalGlobalMemCore7;
    break;
    }

  pInternalScratchMemory = internalScratchMemory;
  internalScratchMemorySize = INTERNAL_SCRATCH_MEM_SIZE;

  for (i = 0; i < n; i++)
    {

      allocateMemTabRequest(&memTab[i]);

      if (memTab[i].base == NULL)
        {
          _ALG_freeMemory(memTab, i);
          return (FALSE);
        }

      memset(memTab[i].base, 0, memTab[i].size);

      printf(
          "algAlloc supplied: Buffer %d: space = %d, attr = %d, size = %ld \n",
          i, memTab[i].space, memTab[i].attrs, memTab[i].size);
    }

  return (TRUE);
}

/*
 *  ======== _ALG_freeMemory ========
 */
Void
_ALG_freeMemory(IALG_MemRec memTab[], Int n)
{
  Int i;

  for (i = 0; i < n; i++)
    {
      if (memTab[i].base != NULL)
        {
          /* XXX changing code here too. to take care of internal memory
           * allocatiuons */
          freeMemTabRequest(&memTab[i]);
        }
    }
}



/*
 *  ======== ALG_create ========
 */
#include <stdio.h>
#include <stdlib.h>
#define SIUVCT_MAX_NUM_ALG_BUFFS  64

static int iVideo = 0;
char memTabMemory_local[SIUVCT_MAX_NUM_ALG_BUFFS * sizeof(IALG_MemRec)*2];   //969



IALG_Handle
ALG_create(IALG_Fxns *fxns, IALG_Handle p, IALG_Params *params)
{


  IALG_MemRec *memTab;
  Int i, n, ret;
  IALG_Handle alg;
  IALG_Fxns *fxnsPtr;

  printf("FYI: Attrs     | Val \n");
  printf("     SCRATCH   |  %d  \n", IALG_SCRATCH);
  printf("     PERSIST   |  %d  \n", IALG_PERSIST);
  printf("     WRITEONCE |  %d  \n", IALG_WRITEONCE);

  if (fxns != NULL)
    {

      errorNumber = iVideo + 100;
      n = ((fxns->algNumAlloc != NULL) ? fxns->algNumAlloc() : IALG_DEFMEMRECS);
      /* The cores cannot share memtab memory */
      //memTab = (IALG_MemRec *)memTabMemory;
      memTab = (IALG_MemRec *) memTabMemory_local
          + (SIUVCT_MAX_NUM_ALG_BUFFS * sizeof(IALG_MemRec) * iVideo);

      if (memTab != NULL)
        {

          n = fxns->algAlloc(params, &fxnsPtr, memTab);
          printf("Num. buffs requested = %d \n", n);

          if (n <= 0)
            {
              errorNumber = -81;
              printf("Num buffs requested is less than or equal to zero!\n");
              return (NULL);
            }

          //errorNumber = 90;

          if (n > SIUVCT_MAX_NUM_ALG_BUFFS)
            {
              printf(
                  "Num buffs requested (%d) is greater than number of supported buffers (%d)!\n",
                  n, 40);
              errorNumber = -82;
              return (NULL);
            }

          for (i = 0; i < n; i++)
            {
              printf(
                  "algAlloc req. Buffer %d: space = %d, attr = %d, size = %ld \n",
                  i, memTab[i].space, memTab[i].attrs, memTab[i].size);
              fflush(stdout);
            }
          if (!iVideo)
            {

              if (_ALG_allocMemory(memTab, n) != FALSE)
                {

                  alg = (IALG_Handle) memTab[0].base;
                  alg->fxns = fxns;
                  if ((ret = fxns->algInit(alg, memTab, p, params)) == IALG_EOK)
                    {
                      return (alg);
                    }
                  printf("algInit() returned error! %d\n", ret);
                  fxns->algFree(alg, memTab);
                  _ALG_freeMemory(memTab, n);
                }
              else
                {
                  errorNumber = -83;
                  printf("Could not allocate memory\n");
                }
            }

        }
    }
  iVideo++;
  return (NULL);

}





/*
 *  ======== ALG_delete ========
 */
Void
ALG_delete(IALG_Handle alg)
{
  IALG_MemRec *memTab;
  Int n;
  IALG_Fxns *fxns;
  char memTabMemory_local[SIUVCT_MAX_NUM_ALG_BUFFS * sizeof(IALG_MemRec)];

  if ((alg != NULL) && (alg->fxns != NULL))
    {
      fxns = alg->fxns;
      n = ((fxns->algNumAlloc != NULL) ? fxns->algNumAlloc() : IALG_DEFMEMRECS);

      memTab = (IALG_MemRec *) memTabMemory_local;
      if (memTab != NULL)
        {
          memTab[0].base = alg;
          n = fxns->algFree(alg, memTab);
          _ALG_freeMemory(memTab, n);
        }
    }
}

/*
 *  ======== ALG_control ========
 */
Int
ALG_control(IALG_Handle alg, IALG_Cmd cmd, IALG_Status *statusPtr)
{
  if ((alg) && (alg->fxns->algControl))
    {
      return (alg->fxns->algControl(alg, cmd, statusPtr));
    }

  return (IALG_EFAIL);
}

/* nothing past this point */
