NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
C2000 CLA C Compiler
The CLA Compiler[edit]
The goal of the CLA compiler is to implement enough of the C programming environment to make it easier to access the capabilities of the CLA architecture and to make it easier to integrate CLA task code and data into a C28x application.
CLA C Language Support[edit]
The CLA compiler supports much of the C language, but not all of it. All the details are in the chapter titled CLA Compiler in the C28x compiler manual (PDF) (HTML).
Getting Started[edit]
Create Your Own Project[edit]
- The simplest way to start writing code is to copy over an existing project (from the header files CLA C examples) and to edit it. Lets take an example: I would like to create a new test, atan, from an existing test case exp2.
- Copy a Project:
- Make a copy of the exp2 folder in the test directory and rename it to atan
- Make a copy of the exp2 folder in the test directory and rename it to atan
- Rename Files:
- Edit the Project Files:
- Open the .cdtbuild and .project files in any text editor and replace all instances of the word exp2 with atan.
- This will ensure all the object files come out with the correct name and any directory dependencies are taken care of.
- Each project has a predefined symbol, TEST_NAME=<test_name>. For e.g. the exp2 project will have a predefined symbol, TEST_NAME=exp2. By altering the .cdtbuild files in the manner described you wont have to change the build settings for each new project .
- Import the Project:
- Modify the Source:
- Edit the test specific source files.
Suggested Build and Link Options[edit]
- The following table lists build and link options that may be useful/instructive for CLA C code. You can setup build properties that apply only to *.cla file by right clicking the file and selecting Properties->C/C++ Build.
Option | Notes |
Basic Options->Debugging Model->Full Symoblic debug (-g) | If you would like to access watch variables etc while debugging.
|
Basic Options->Debugging Model->Suppress all symbolic debug information | View compiler generated assembly code without all the debug information.This is useful when estimating the cycle count for a small routine. |
Basic Options->Optimization Level = none - O2 | ![]() |
Assembly Options -> Keep generated assembly files (-k) | Useful if you want to compare compiler generated code with hand coded assembly. |
Linker Options-> Diagnostics -> --diag_suppress=16002 |
![]() |
C Language Tips and Tricks[edit]
Dealing with Pointers[edit]
- Pointers are interpreted differently on the C28x and the CLA. The C28x treats them as 32-bit data types (address bus size being 22-bits wide can only fit into a 32-bit data type) while the CLA only has an address bus size of 16 bits. Assume the following structure is declared in a shared header file(i.e. common to the C28 and CLA) and defined and allocated to a memory section in a .c file
<syntaxhighlight lang="c"> /******************************************************************** Shared Header File
- /
typedef struct{
float a; float *b; float *c;
}foo; /******************************************************************** main.c
- /
- pragma(X,"CpuToCla1MsgRam") //Assign X to section CpuToCla1MsgRam
foo X; /******************************************************************** test.cla
- /
__interrupt void Cla1Task1 ( void ) {
float f1,f2; f1 = *(X.b); f2 = *(X.c); //Pointer incorrectly dereferenced //Tries to access location 0x1503 instead //of 0x1504
} </syntaxhighlight>
- Assume that the C28 compiler will allocate space for X at the top of the section CpuToCla1MsgRam as follows:
Element | Address |
---|---|
X.a | 0x1500 |
X.b | 0x1502 |
X.c | 0x1504 |
- The CLA compiler will interpret this structure differently
Element | Address |
---|---|
X.a | 0x1500 |
X.b | 0x1502 |
X.c | 0x1503 |
- The CLA compiler treats pointers b and c as 16-bits wide and, therefore, incorrectly de-references pointer c. The solution to this is to declare a new pointer as follows:
<syntaxhighlight lang="c"> /******************************************************************** Shared Header File
- /
typedef union{
float *ptr; //Aligned to lower 16-bits Uint32 pad; //32-bits
}CLA_FPTR;
typedef struct{
float a; CLA_FPTR b; CLA_FPTR c;
}foo;
/******************************************************************** main.c
- /
- pragma(X,"CpuToCla1MsgRam") //Assign X to section CpuToCla1MsgRam
foo X; /******************************************************************** test.cla
- /
__interrupt void Cla1Task1 ( void ) {
float f1,f2; f1 = *(X.b.ptr); f2 = *(X.c.ptr); //Correct Access
} </syntaxhighlight>
- The new pointer CLA_FPTR is a union of a 32-bit integer and a pointer to a float. The CLA compiler recognizes the size of the larger of the two elements(the 32 bit integer) and therefore aligns the pointer to the lower 16-bits. Now both the pointers b and c will occupy 32-bit memory spaces and any instruction that tries to de-reference pointer c will access the correct address 0x1504.
Profiling[edit]
- The CLA does not support the clock function and therefore it is not possible to get a direct cycle count of a particular task. The user can configure the time base module on an ePWM to keep track of the execution time of a task
- Setup the time base of ePWM1(or any ePWM) to run at SYSCLKOUT in the up-count mode as shown below:
<syntaxhighlight lang="c"> void InitEPwm(void) {
// Setup TBCLK EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up EPwm1Regs.TBPRD = 0xFFFF; // Set timer period EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0 EPwm1Regs.TBCTR = 0x0000; // Clear counter EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
} </syntaxhighlight>
- Proceed to define two macros READ_CLOCK and RESTART_CLOCK, the former to freeze the ePWM timer and copy the elapsed time to a variable, and the latter to restart the ePWM timer.
<syntaxhighlight lang="c">
- define READ_CLOCK(X) __meallow();\
EPwm1Regs.TBCTL.bit.CTRMODE = TB_FREEZE;\ X = EPwm1Regs.TBCTR;\ __medis();
- define RESTART_CLOCK __meallow();\
EPwm1Regs.TBCTL.bit.CTRMODE = TB_FREEZE;\ EPwm1Regs.TBCTR = 0;\ EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP;\ __medis();
</syntaxhighlight>
- Define a variable e.g. ulCycleCount to hold the cycle count
<syntaxhighlight lang="c">
- pragma DATA_SECTION(ulCycleCount,"Cla1ToCpuMsgRAM");
unsigned long ulCycleCount; </syntaxhighlight>
- Place the macro RESTART_CLOCK at the beginning of a task to restart the ePWM timer and place READ_CLOCK at the end of the task to read the value of the timer. The elapsed time will be give you the cycle count plus a minimal overhead from the two macros
<syntaxhighlight lang="c"> __interrupt void Cla1Task1 ( void ) {
//Local Variables float a; __mdebugstop(); RESTART_CLOCK; a = 10; ... ... ... READ_CLOCK(ulCycleCount);
}
</syntaxhighlight>
Debugging[edit]
- The user can follow these steps to start debugging their code on the CLA
- Add _mdebugstop()
- Place an __mdebugstop() at the beginning of the CLA task you wish to debug. For example task 1 of exp2.cla.
- Set build options:
- You can setup individual build properties for the *.cla file seperately from the rest of the application.
- Right click the .cla file and select Properties->C/C++ Build.
- Connect to the CLA:
- Once you have built your project and launched the debug session CCS, by default, will connect to only the C28 core.
- To be able to debug CLA code you will need to connect to the CLA core.
Note: Build the code with -g (Full Symbolic Debug) to generate the symbols that will be loaded to the debugger.
- Run the C28x:
- In the exp2 example we have enabled task 1 of the CLA and we trigger it in software on the C28 side. When we run the code on the C28 debug session it seems to stall at the Cla1ForceTask1andWait() routine. It is waiting for the CLA task 1 to run to completion. When we switch over to the CLA session we see that execution has stopped at the __mdebustop() intrinsic
- In the exp2 example we have enabled task 1 of the CLA and we trigger it in software on the C28 side. When we run the code on the C28 debug session it seems to stall at the Cla1ForceTask1andWait() routine. It is waiting for the CLA task 1 to run to completion. When we switch over to the CLA session we see that execution has stopped at the __mdebustop() intrinsic
- Debug the Code:
- At this point we can proceed to single step through the code.
- There are some restrictions to debugging the CLA and they are discussed next.
Known Debugging Issues[edit]
- The CLA pipeline is not flushed on a single step and so results may not be visible until a few instructions later. Please refer to the CLA user guide for more details about the pipeline.
- If you plan to debug (single step) code on the CLA it is necessary that MNOPs are placed prior to any MSTOP to ensure the instructions prior to the MSTOP proceed through the pipeline before the MSTOP executes. The compiler will insert these MNOPs if compiling with debug (-g). The MNOPs are unnecessary if you are not debugging the CLA code.(This behavior was verified when running the exp2 project)
- Run-to-Line is not supported. Step over works the same as Step into
Compiler Software Collateral[edit]
All CLA supported devices will have several demos in the examples folder under their respective device_support directories
Tutorials[edit]
The following tutorials are available (zip file below) to help you get started with the CLA compiler. The videos can be accessed from the training site (focus.ti.com/docs/training/catalog/events/event.jhtml) or downloaded from the link below
- Tutorial 1: Compiler Basics
- Tutorial 2: Example Code Structure
- Tutorial 3: Demo
- Tutorial 4: Debugging
DOWNLOAD LINK:Tutorial Videos (.zip)
Important Links
[edit]
CLA C Compiler Training Series
https://training.ti.com/c2000-cla-c-compiler-4-part-series