/*****************************************************************************
 *
 * set_c.asm : $Revision: 1.8.24.1 $
 *
 * Copyright (C) 1998-2011 Analog Devices, Inc. All Rights Reserved.
 *
 *****************************************************************************/

#if defined(__DOCUMENTATION__)

   Function: ___lib_setup_c
             - initialize processor, memory and library for C applications

   Synopsis:

   Description:

      Called from the reset interrupt.

   Error conditions:

   Implementation Notes:

 *****************************************************************************
#endif

#if !defined(__NO_LIBRARY_ATTRIBUTES__)
.FILE_ATTR libGroup="startup";
.FILE_ATTR libName="libc";
.FILE_ATTR libFunc="___lib_setup_c";
.FILE_ATTR FuncName="___lib_setup_c";
.FILE_ATTR libFunc="___lib_setup_heaps";
.FILE_ATTR FuncName="___lib_setup_heaps";
.FILE_ATTR libFunc="___lib_setup_runtime_heap";
.FILE_ATTR FuncName="___lib_setup_runtime_heap";
.file_attr libFunc="___lib_sure_rts";
.file_attr FuncName="___lib_sure_rts";
.FILE_ATTR prefersMem="internal";
.FILE_ATTR prefersMemNum="30";
#endif

#include <sys/anomaly_macros_rtl.h>
#include <platform_include.h>
#include "sig_glob.h"
#if defined(__SIMDSHARC__)
#include "linkports.h"
#endif

#define MAXHEAPS 4        // The maximum number of run-time heaps
#define SIZEOF_HEAPINFO 5 // sizeof heapinfo structure

.EXTERN ldf_stack_space, ldf_stack_length;  // defined in the LDF
.EXTERN ___lib_heap_space;  // defined in the LDF
.EXTERN __heaps, __num_heaps;
.EXTERN ___inits;
.EXTERN ___lib_setup_args;
.EXTERN ___lib_int_table;
#ifdef _ADI_SWFA
.EXTERN __21160_anomaly_write_location;
#endif

.GLOBAL ___lib_setup_c;
.GLOBAL   ___lib_sure_rts;
.GLOBAL ___lib_setup_runtime_heap;
.GLOBAL ___ctor_NULL_marker;
.RETAIN_NAME ___ctor_NULL_marker;

.SECTION/DATA/DOUBLEANY seg_ctdml;  // The ldf places this after seg_ctdm

.VAR ___ctor_NULL_marker = 0;

.SECTION/CODE/DOUBLEANY seg_pmco;

___lib_setup_c:                    // called using a CALL instruction
#if !defined(__ADSP21020__)
      /* Enable the instruction cache. */
      BIT SET MODE2 CADIS;         // disable cache
#if WA_07000008
      /* Instruction Cache needs to be initialized */
      NOP;                         // MODE2 latency
      READ CACHE 0;                // read cache instruction
#endif
      FLUSH CACHE;
      BIT CLR MODE2 CADIS;         // enable the cache
#endif
 
      /* clear latched or pointer interrupts register bits */
#if defined(__SIMDSHARC__)
      LIRPTL = 0;
      IMASKP = 0;
#endif
      IRPTL = 0;

      /* setup compiler registers */
      LCNTR = 2, do (PC, regs_setup) until LCE;
            M15 = -1;
			   M7 = -1;
			   M14 = 1;
			   M6 = 1;
			   M13 = 0;
			   M5 = 0;
			   L0 = 0;
			   L1 = 0;
			   L2 = 0;
			   L3 = 0;
			   L4 = 0;
			   L5 = 0;
            /* L6 and L7 initialized below for stack accesses */
			   L8 = 0;
			   L9 = 0;
			   L10 = 0;
			   L11 = 0;
			   L12 = 0;
			   L13 = 0;
			   L14 = 0;
			   L15 = 0;
            /* set up stack ensuring that it is 2 word aligned */
            B7 = ldf_stack_space;
            I7 = (  (ldf_stack_space + ldf_stack_length - 1)
                  - ((ldf_stack_space + ldf_stack_length - 1) % 2) );
            L7 = (  ldf_stack_length
                  - ((ldf_stack_space + ldf_stack_length - 1) % 2) );
            B6 = B7;
            I6 = I7;
            L6 = L7;
            BIT SET MODE1 (SRD1H|SRD1L|SRD2H|SRD2L);	// enable secondary dags
regs_setup: NOP;                 // MODE1 change latency

                                 // reset to primary dags and setup modes for C
#if defined(__ADSP21020__)
      BIT CLR MODE1 (SRD1H|SRD1L|SRD2H|SRD2L|ALUSAT|TRUNC);
#else
      BIT CLR MODE1 (SRD1H|SRD1L|SRD2H|SRD2L|ALUSAT|TRUNCATE);
#endif
#if defined(__SIMDSHARC__)
      BIT SET MODE1 (NESTM|IRPTEN|RND32|CBUFEN);

                                 // set MMASK to disable interrupts, saturation,
                                 // SIMD, broadcast loads, bit reversal and 
                                 // TRUNCATE for interrupts.
      MMASK = (BR8|BR0|IRPTEN|ALUSAT|TRUNCATE|PEYEN|BDCST9|BDCST1);
#else
      BIT SET MODE1 (NESTM|IRPTEN|RND32);
#endif
 
      /* setup memory */
___lib_setup_memory:   
      /* The MODE1 change above will not impact the following load so
      ** suppress the assembler warning for anomaly 09000022/15000004
      ** which is concerned with the effect latence of changed to MODE1
      ** being 2 ctcles thater than 1.
      */ 
      .MESSAGE/SUPPRESS 2547 for 1 lines;
      PX = PM(___inits);     // Read address of table
      R0 = PX2;
      R0 = PASS R0,          // test for no initialization data
         I8 = R0;            // I8 points to init data
      IF EQ JUMP finish_inits; // done, there are no inits
         
zero_dm:      
      PX = PM(I8, M14);      // read number of DM zero inits
      R0 = PX2;
      R0 = PASS R0;          // test for no DM zero inits
      IF EQ JUMP (PC, zero_pm); // no DM zero inits
      LCNTR = R0, DO zero_inits_dm UNTIL LCE;
         PX = PM(I8, M14);   // read zero init block
         I0 = PX2;           // load pointer to block begin
#if defined(__SIMDSHARC__)
         R0 = PX1;
         R0 = FEXT R0 BY 16:16;
         LCNTR = R0, DO zero_blk_dm UNTIL LCE;
#else
         LCNTR = PX1, DO zero_blk_dm UNTIL LCE;
#endif
zero_blk_dm:    DM(I0, M6) = 0;
zero_inits_dm: NOP;

zero_pm:      
      PX = PM(I8, M14);      // read number of PM zero inits
      R0 = PX2;
      R0 = PASS R0;          // test for no PM zero inits
      IF EQ JUMP (PC, init_dm); // no PM zero inits
      LCNTR = R0, DO zero_inits_pm UNTIL LCE; 
        PX = PM(I8, M14);    // read zero init block
        I9 = PX2;            // Load pointer to block begin
        R0 = PX1;
#if defined(__SIMDSHARC__)
        R0 = FEXT R0 BY 16:16;
#endif
        PX=0;
        LCNTR = R0, DO zero_blk_pm UNTIL LCE; 
#if defined(__WORKAROUND_2126X_ANOMALY4__) || WA_15000016
             /* Avoid a 1 instruction loop using PM access or a 2 instruction 
             ** loop where the PM access is the second instruction 
             */
             PM(I9, M14)=PX;  // 48 bits init 
zero_blk_pm: NOP;
#else
zero_blk_pm: PM(I9, M14)=PX;  // 48 bits init
#endif
#ifdef _ADI_SWFA
             PM(__21160_anomaly_write_location) = R0;
             PM(__21160_anomaly_write_location) = R0;
#endif
zero_inits_pm: NOP;

init_dm:      
      PX = PM(I8, M14);      // read number of DM blk inits
      R0 = PX2;
      R0 = PASS R0;          // Check for no DM blk inits
      IF EQ JUMP (PC, init_pm); // Do PM inits
      LCNTR = R0, DO blk_inits_dm UNTIL LCE;
         PX = PM(I8, M14);   // read address and count
         I0 = PX2;           // set beginning address
#if defined(__SIMDSHARC__)
         R0 = PX1;
         R0 = FEXT R0 BY 16:16;
         LCNTR = R0, DO init_blk_dm UNTIL LCE;
#else
         LCNTR = PX1, DO init_blk_dm UNTIL LCE;
#endif
             PX = PM(I8, M14);
             R0 = PX2;
init_blk_dm: DM(I0, M6) = R0;
blk_inits_dm: NOP;

init_pm:      
      PX = PM(I8, M14);      // read number of PM blk inits
      R0 = PX2;
      R0 = PASS R0;          // Check for no PM blk inits
      IF EQ jump finish_inits; // done
      LCNTR = R0, DO blk_inits_pm UNTIL LCE;
         PX = PM(I8, M14);   // read address and count
         I9 = PX2;           // point to blk begin
#if defined(__SIMDSHARC__)
         R0 = PX1;  
         R0 = FEXT R0 BY 16:16;
         LCNTR = R0, DO init_blk_pm UNTIL LCE;
#else
         LCNTR = PX1, DO init_blk_pm UNTIL LCE;
#endif
            PX = PM(I8, M14);
#if defined(__2126x__) && defined(__WORKAROUND_2126X_ANOMALY4__)
            NOP;             // avoids a 2 instruction loop that might 
                             // iterate once (anomaly 06000012 case 3)
#endif
#ifdef _ADI_SWFA
             PM(I9, M14) = PX;
             PM(__21160_anomaly_write_location) = r0;
init_blk_pm: PM(__21160_anomaly_write_location) = r0;
#else
init_blk_pm: PM(I9, M14) = PX; 
#endif
blk_inits_pm: NOP;

finish_inits:
.___lib_setup_memory.end:

#ifndef _ADI_THREADS

.EXTERN ___lib_sure_rti;

      /* setup interrupt support */
___lib_setup_ints:  
      R2=1;                       /* Mask defaults             */
      R8=0xffffffff;
      R4=___lib_sure_rti;         /* Default interrupt handler */
      R1=___lib_sure_rts;         /* Default functions         */
      I4=___lib_int_table;

#if next_mask != 0
#error this code assumes that next_mask is zero
#endif

#if defined(__ADSP21020__) || defined(__2106x__)
     LCNTR=___SIG_LAST_HARDWARE_INT+1, DO default_int_table UNTIL LCE;
        R0=NOT R2,
           DM(curr_func,I4)=R1;
        R2=LSHIFT R2 BY 1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R0;
default_int_table:    
        DM(I4, siga_size)=R0;  /* write next_mask filed (zero offset) 
                                  using a post-modify */

#elif defined(__2116x__)
// for setting up the 2116x table need to treat the link
// port interrupts specially.  Also, for the hardware 
// interrupts after the link port interrupts, need to 
// account for the shift in number

     LCNTR=FIRST_LINK_PORT, DO low_int_table UNTIL LCE;
        R0=NOT R2,
           DM(curr_func,I4)=R1;
        R2=LSHIFT R2 BY 1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R0;
low_int_table:    
        DM(I4, siga_size)=R0;  /* write next_mask filed (zero offset) 
                                  using a post-modify */

     LCNTR=SIG_EP0I-SIG_LP0I, DO liprt_int_table UNTIL LCE;
        DM(curr_func,I4)=R1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R8;
liprt_int_table:    
        DM(I4, siga_size)=R8;  /* write next_mask filed (zero offset) 
                                  using a post-modify */
     
     r2=LSHIFT R2 BY 1;        // account for LPISUM

     LCNTR=___SIG_LAST_HARDWARE_INT-LAST_LINK_PORT, DO high_int_table UNTIL LCE;
        R0=NOT R2,
           DM(curr_func,I4)=R1;
        R2=LSHIFT R2 BY 1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R0;
high_int_table:
        DM(I4, siga_size)=R0;  /* write next_mask filed (zero offset) 
                                  using a post-modify */

#elif defined(__SIMDSHARC__) & !defined(__2116x__)
// for setting up the 2136x table need to treat the link  port interrupts
// specially.  Also, for the hardware interrupts between and after the link
// port interrupts, need to account for the shift in number

     LCNTR=FIRST_START_LINK_PORT, DO low_int_table UNTIL LCE;
        R0=NOT R2,
           DM(curr_func,I4)=R1;
        R2=LSHIFT R2 BY 1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R0;
low_int_table:
        DM(I4, siga_size)=R0;  /* write next_mask filed (zero offset) 
                                  using a post-modify */
     
     LCNTR=FIRST_END_LINK_PORT-FIRST_START_LINK_PORT+1, DO low_liprt_int_table UNTIL LCE;
        DM(curr_func,I4)=R1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R8;
low_liprt_int_table:
        DM(I4, siga_size)=R8;  /* write next_mask filed (zero offset) 
                                  using a post-modify */

     LCNTR=LAST_START_LINK_PORT-FIRST_END_LINK_PORT-1, DO med_int_table UNTIL LCE;
        R0=NOT R2,
           DM(curr_func,I4)=R1;
        R2=LSHIFT R2 BY 1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R0;
med_int_table:
        DM(I4, siga_size)=R0;  /* write next_mask filed (zero offset) 
                                  using a post-modify */

     LCNTR=LAST_END_LINK_PORT-LAST_START_LINK_PORT+1, DO high_liprt_int_table UNTIL LCE;
        DM(curr_func,I4)=R1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R8;
high_liprt_int_table:
        DM(I4, siga_size)=R8;  /* write next_mask filed (zero offset) 
                                  using a post-modify */

     LCNTR=___SIG_LAST_HARDWARE_INT-LAST_END_LINK_PORT, DO high_int_table UNTIL LCE;
        R0=NOT R2,
           DM(curr_func,I4)=R1;
        R2=LSHIFT R2 BY 1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;
        DM(defl_mask,I4)=R0;
high_int_table:
        DM(I4, siga_size)=R0;  /* write next_mask filed (zero offset) 
                                  using a post-modify */
#endif 

     R1=SIG_IGN;
     LCNTR=___SIG_LAST_INTERRUPT - ___SIG_LAST_HARDWARE_INT, DO sw_int_table UNTIL LCE;
        DM(curr_func,I4)=R1;
        DM(next_func,I4)=R1;
        DM(defl_func,I4)=R1;
        DM(defl_disp,I4)=R4;   // for s/w ints this should neve be called
        DM(defl_mask,I4)=R8;
sw_int_table:
        DM(I4, siga_size)=R8;  /* write next_mask filed (zero offset) 
                                  using a post-modify */
___lib_setup_ints.end:
#endif /* _ADI_THREADS */

___lib_init_heaps:
      /* initialize heaps 
      ** - reset the __heaps to zero
      ** - clear the info for run-time installed heaps.
      ** - setup static heaps
      */
/*
  typedef struct {
    char *seg_;
    char *heap;
    unsigned long userid;
    char *base;
    size_t length;
  } heapinfo;
*/

      I12 = __heaps;
      PX = 0;
      LCNTR = (SIZEOF_HEAPINFO * MAXHEAPS), DO heap_zero UNTIL LCE;
#if defined(__WORKAROUND_2126X_ANOMALY4__) || WA_15000016
             /* Avoid a 1 instruction loop using PM access or a 2 instruction 
             ** loop where the PM access is the second instruction 
             */
           PM(I12, M14) = PX;  // __heaps[i] = 0;
heap_zero: NOP;
#else
heap_zero: PM(I12, M14) = PX;  // __heaps[i] = 0;
#endif
      DM(__num_heaps) = M5;
___lib_init_heaps.end:

      CALL ___lib_setup_heaps;

      JUMP ___lib_setup_args;   // return eliminated
.___lib_setup_c.end:

___lib_setup_runtime_heap:
      JUMP (pc, .loop_thru_heaps_p1)(db);
         PX = PM(0, I12);
         nop;
.___lib_setup_runtime_heap.end:

___lib_setup_heaps:
      I12 = ___lib_heap_space;
loop_thru_heaps:
      /* Check that we have a valid heap */
#if defined(__21160_GLITCH)
      NOP;
#endif
      PX = PM(0, I12);
.loop_thru_heaps_p1:
      R0 = PX2;
      R0 = PASS R0;
      IF EQ RTS;
      /* Ensure that heap is suitably aligned for SIMD
         accesses, and that length is also suitable. */
      PX = PM(4, I12);            // Get heap length
      R1 = PX2;
      PX = PM(3, I12);            // Get heap start
      R0 = PX2;

      BTST R0 BY 0;               // Check if heap start is odd
      IF NOT sz R0 = R0 + 1;         // If so, start++
      IF NOT sz R1 = R1 - 1, PX2=R0; // and length--

      PM(3, I12) = PX;            // Write heap start
      PX2 = R1;     
      PM(4, I12) = PX;            // Write heap length
      
      /* Is this a PM or a DM heap. If it's PM, PX1 will hold 1, DM is -1. */
      PX = PM(1, I12);
      R0 = PX1;
      PX = PM(4, I12);
      R1 = R0 - 1, R0 = PX2;
      IF EQ JUMP (PC, pm_heap) (DB);
         PX = PM(3, I12);
         R1 = PX2;
 
      I4 = R1;
      MODIFY(I12, 5);
      R2=3;
      R1=R1+R2;
      R2=2;
      R0=R0-R2, R2=I12;
      DM(I4, M6)= 0;
      DM(I4, M6) = R1;
      DM(I4, M6) = R1;    // Dummy write
      R0=R0-1,DM(I4, M6) = R0;
      R0=R0-1;            // Leave space for a control block at the end...
      JUMP (PC, loop_thru_heaps) (DB);
         DM(I4, M6) = 0;
         DM(I4, M5) = R0;

pm_heap:        
      MODIFY(I12, 5);
      R2=I12;
      R3=3;
      R1=R1+R3, I12 = R1;
      R3=5;
      R0=R0-R3;
      PM(I12, M14) = 0;    // Writing does not need to change
      PM(I12, M14) = R1;   // because stacks/heaps are 32bits
      PM(I12, M14) = R1;   // Dummy write
      R0=R0-1,PM(I12, M14) = R0;
      PM(I12, M14) = 0;
      R0=R0-1;             // Leave space for a control block at the end...
      JUMP (PC, loop_thru_heaps) (DB);
         PM(I12, M13) = R0;
         I12 = R2;
___lib_setup_heaps.end:

___lib_sure_rts:
      NOP;                // Need to ensure 2 non-reads
      I12 = DM(M7, I6);   // fetch the return address
      NOP;
      JUMP (M14, I12) (DB);  // return
         I7 = I6;
         I6 = DM(0, I6);
.___lib_sure_rts.end:
