//###########################################################################
//
// FILE:   cla_mixed_c_asm_cpu01.c
//
// TITLE:  CLA Mixed C and Assembly Code Example for F2837xD.
//
//! \addtogroup cpu01_example_list
//! <h1>CLA Mixed C and Assembly Code (cla_mixed_c_asm_cpu01)</h1>
//!
//! This example shows the use of both C and assembly code on the CLA. The
//! arc-cosine function uses a table lookup method and polynomial interpolation
//! to determine the angle corresponding to the argument. The tables are stored
//! in the CLA data ROM.
//!
//! The tables needed by the acos routine are located in the CLA data ROM.
//! A symbol table library is included with this example: \n
//!          c1bootROM_CLADataROMSymbols(_fpu32).lib \n
//! The user must add this to the inclusion list in the upper window of the
//! "File Search Path" options which can be found under
//!          "properties->c2000 linker->File Search Path" \n
//! Since this library is present in the source directory, the user must also
//! add the search path to the bottom window
//!          "${PROJECT_ROOT}/../"
//!
//! \b Watch \b Variables \n
//!  - y1 - Accumulated results (angles in radians) from C routine
//!  - y2 - Accumulated results (angles in radians) from asm routine
//!
//
//###########################################################################
// $TI Release: F2837xD Support Library v210 $
// $Release Date: Tue Nov  1 14:46:15 CDT 2016 $
// $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

//
// Included Files
//
#include "F28x_Project.h"
#include "cla_mixed_c_asm_shared.h"

//
// Defines
//
#define WAITSTEP     asm(" RPT #255 || NOP")

//
// Globals
//

//
//Task 1 (C) Variables
//
float y1[BUFFER_SIZE+1];
float y2[BUFFER_SIZE+1];

#ifdef __cplusplus
#pragma DATA_SECTION("CpuToCla1MsgRAM")
float fVal;
#pragma DATA_SECTION("Cla1ToCpuMsgRAM")
float fResult;
#else
#pragma DATA_SECTION(fVal,"CpuToCla1MsgRAM")
float fVal;
#pragma DATA_SECTION(fResult,"Cla1ToCpuMsgRAM")
float fResult;
#endif // __cplusplus

//
//Golden Test Values
//
float acos_expected[BUFFER_SIZE]={
    0, 0.1770077, 0.2506557, 0.3073950, 0.3554212,
    0.3979045, 0.4364690, 0.4720786, 0.5053605, 0.5367502,
    0.5665643, 0.5950419, 0.6223685, 0.6486915, 0.6741305,
    0.6987840, 0.7227343, 0.7460509, 0.7687935, 0.7910135,
    0.8127556, 0.8340589, 0.8549583, 0.8754844, 0.8956648,
    0.9155242, 0.9350851, 0.9543675, 0.9733899, 0.9921693,
    1.010721, 1.029059, 1.047198, 1.065148, 1.082921,
    1.100529, 1.117980, 1.135284, 1.152450, 1.169486,
    1.186400, 1.203198, 1.219889, 1.236478, 1.252973,
    1.269378, 1.285700, 1.301944, 1.318116, 1.334221,
    1.350263, 1.366248, 1.382180, 1.398064, 1.413903,
    1.429704, 1.445469, 1.461202, 1.476908, 1.492592,
    1.508256, 1.523904, 1.539541, 1.555171
};

uint16_t pass=0;
uint16_t fail=0;

//
// Function Prototypes
//
void CLA_runTest(void);
void CLA_configClaMemory(void);
void CLA_initCpu1Cla1(void);
__interrupt void cla1Isr1();
__interrupt void cla1Isr2();
__interrupt void cla1Isr3();
__interrupt void cla1Isr4();
__interrupt void cla1Isr5();
__interrupt void cla1Isr6();
__interrupt void cla1Isr7();
__interrupt void cla1Isr8();

//
// Main
//
void main(void)
{
//
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xD_SysCtrl.c file.
//
    InitSysCtrl();

//
// Step 2. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
//
    DINT;

//
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the F2837xD_PieCtrl.c file.
//
    InitPieCtrl();

//
// Disable CPU interrupts and clear all CPU interrupt flags:
//
    IER = 0x0000;
    IFR = 0x0000;

//
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in F2837xD_DefaultIsr.c.
// This function is found in F2837xD_PieVect.c.
//
    InitPieVectTable();

//
// Step 3. Configure the CLA memory spaces first followed by
// the CLA task vectors
//
    CLA_configClaMemory();
    CLA_initCpu1Cla1();

//
// Step 4. Enable global Interrupts and higher priority real-time debug events:
//
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

//
// Step 5. Run the test
//
    CLA_runTest();
}

//
// CLA_runTest - Execute CLA task tests for specified vectors
//
void CLA_runTest(void)
{
    int16_t i;
    float fError[BUFFER_SIZE+1], fError1[BUFFER_SIZE+1];

    for(i=0; i < BUFFER_SIZE; i++)
    {
        fVal = (float)(BUFFER_SIZE - i)/(float)BUFFER_SIZE;

        Cla1ForceTask1andWait();
        WAITSTEP;

        y1[i] = fResult;
        fError[i] = 0.0;
        fError[i] = fabs(acos_expected[i]-y1[i]);

        if(fError[i] < 1e-4)
        {
            pass++;
        }
        else
        {
            fail++;
        }
    }

    fVal = 0.0;
    Cla1ForceTask1andWait();
    WAITSTEP;

    y1[i] = fResult;
    fError[i] = fabs((PI/2)-y1[i]);

    if(fError[i] < 1e-4)
    {
        pass++;
    }
    else
    {
        fail++;
    }

    for(i=0; i < BUFFER_SIZE; i++)
    {
        fVal= (float)(BUFFER_SIZE - i)/(float)BUFFER_SIZE;

        Cla1ForceTask2andWait();
        WAITSTEP;

        y2[i] = fResult;
        fError1[i] = fabs(acos_expected[i]-y2[i]);

        if(fError1[i] < 1e-4)
        {
            pass++;
        }
        else
        {
            fail++;
        }
    }

    fVal = 0.0;
    Cla1ForceTask2andWait();

    y2[i] = fResult;
    fError1[i] = fabs((PI/2)-y2[i]);

    if(fError1[i] < 1e-4)
    {
        pass++;
    }
    else
    {

        fail++;
    }
}

//
// CLA_configClaMemory - Configure CLA memory sections
//
void CLA_configClaMemory(void)
{
    extern uint32_t Cla1funcsRunStart, Cla1funcsLoadStart, Cla1funcsLoadSize;
    EALLOW;

#ifdef _FLASH
    //
    // Copy over code from FLASH to RAM
    //
    memcpy((uint32_t *)&Cla1funcsRunStart, (uint32_t *)&Cla1funcsLoadStart,
           (uint32_t)&Cla1funcsLoadSize);
#endif //_FLASH

    //
    // Initialize and wait for CLA1ToCPUMsgRAM
    //
    MemCfgRegs.MSGxINIT.bit.INIT_CLA1TOCPU = 1;
    while(MemCfgRegs.MSGxINITDONE.bit.INITDONE_CLA1TOCPU != 1){};

    //
    // Initialize and wait for CPUToCLA1MsgRAM
    //
    MemCfgRegs.MSGxINIT.bit.INIT_CPUTOCLA1 = 1;
    while(MemCfgRegs.MSGxINITDONE.bit.INITDONE_CPUTOCLA1 != 1){};

    //
    // Select LS5RAM to be the programming space for the CLA
    // First configure the CLA to be the master for LS5 and then
    // set the space to be a program block
    //
    MemCfgRegs.LSxMSEL.bit.MSEL_LS5 = 1;
    MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS5 = 1;

    //
    // Next configure LS0RAM and LS1RAM as data spaces for the CLA
    // First configure the CLA to be the master for LS0(1) and then
    // set the spaces to be code blocks
    //
    MemCfgRegs.LSxMSEL.bit.MSEL_LS0 = 1;
    MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS0 = 0;

    MemCfgRegs.LSxMSEL.bit.MSEL_LS1 = 1;
    MemCfgRegs.LSxCLAPGM.bit.CLAPGM_LS1 = 0;

    EDIS;
}

//
// CLA_initCpu1Cla1 - Initialize CLA1 task vectors and end of task interrupts
//
void CLA_initCpu1Cla1(void)
{
    //
    // Compute all CLA task vectors
    // On Type-1 CLAs the MVECT registers accept full 16-bit task addresses as
    // opposed to offsets used on older Type-0 CLAs
    //
    EALLOW;
    Cla1Regs.MVECT1 = (uint16_t)(&Cla1Task1);
    Cla1Regs.MVECT2 = (uint16_t)(&Cla1Task2);
    Cla1Regs.MVECT3 = (uint16_t)(&Cla1Task3);
    Cla1Regs.MVECT4 = (uint16_t)(&Cla1Task4);
    Cla1Regs.MVECT5 = (uint16_t)(&Cla1Task5);
    Cla1Regs.MVECT6 = (uint16_t)(&Cla1Task6);
    Cla1Regs.MVECT7 = (uint16_t)(&Cla1Task7);
    Cla1Regs.MVECT8 = (uint16_t)(&Cla1Task8);

    //
    // Enable the IACK instruction to start a task on CLA in software
    // for all  8 CLA tasks. Also, globally enable all 8 tasks (or a
    // subset of tasks) by writing to their respective bits in the
    // MIER register
    //
    Cla1Regs.MCTL.bit.IACKE = 1;
    Cla1Regs.MIER.all = 0x00FF;

    //
    // Configure the vectors for the end-of-task interrupt for all
    // 8 tasks
    //
    PieVectTable.CLA1_1_INT = &cla1Isr1;
    PieVectTable.CLA1_2_INT = &cla1Isr2;
    PieVectTable.CLA1_3_INT = &cla1Isr3;
    PieVectTable.CLA1_4_INT = &cla1Isr4;
    PieVectTable.CLA1_5_INT = &cla1Isr5;
    PieVectTable.CLA1_6_INT = &cla1Isr6;
    PieVectTable.CLA1_7_INT = &cla1Isr7;
    PieVectTable.CLA1_8_INT = &cla1Isr8;

    //
    // Enable CLA interrupts at the group and subgroup levels
    //
    PieCtrlRegs.PIEIER11.all = 0xFFFF;
    IER |= (M_INT11 );
}

//
// cla1Isr1 - CLA1 ISR 1
//
__interrupt void cla1Isr1 ()
{
    //
    // Acknowledge the end-of-task interrupt for task 1
    //
    PieCtrlRegs.PIEACK.all = M_INT11;
//    asm(" ESTOP0");
}

//
// cla1Isr2 - CLA1 ISR 2
//
__interrupt void cla1Isr2 ()
{
    //
    // Acknowledge the end-of-task interrupt for task 2
    //
    PieCtrlRegs.PIEACK.all = M_INT11;
//    asm(" ESTOP0");
}

//
// cla1Isr3 - CLA1 ISR 3
//
__interrupt void cla1Isr3 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr4 - CLA1 ISR 4
//
__interrupt void cla1Isr4 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr5 - CLA1 ISR 5
//
__interrupt void cla1Isr5 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr6 - CLA1 ISR 6
//
__interrupt void cla1Isr6 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr7 - CLA1 ISR 7
//
__interrupt void cla1Isr7 ()
{
    asm(" ESTOP0");
}

//
// cla1Isr8 - CLA1 ISR 8
//
__interrupt void cla1Isr8 ()
{
    asm(" ESTOP0");
}

//
// End of File
//
