CC5X C compiler

CC5X
PRICES
BUY NOW
DOWNLOAD

Introduction
Features
- Math library
- Installation
- Supported chips

Examples
FAQ
NEWS red_ball.gif (129 bytes)
Planned
Feedback
Support
Distributors

CC8E
CC7A
Leanslice
Emotor
HOME

 

News

The newest features are listed first. If no new features are listed then the new version cover minor improvements, new device header files and bug fixes.

Version 3.8C released

Version 3.8B released

Warning levels

All warnings has been assigned a level. The levels are numbered 1,2,3. It is possible to decide which warning levels that are printed. This is useful to limit the number of warnings. The current active warning level is decided by option -w.

  LEVEL 1: basic
  LEVEL 2: normal
  LEVEL 3: extra

  -w3 : print warnings from level 1 to 3 (all warnings)
  -w2 : print warnings from level 1 to 2 (default)
  -w1 : print warnings at level 1 only
  -w0 : print no warnings

The default active warning level is 2 (option -w2). The compiler prints the number of warnings at each level:

      Warnings (level 1-3): 2,3,0  [-w2 active]

Warnings that need an option to be printed still needs that option.

Alternative special register bit names

It is possible to use alternative bit names for special function register names inspired by the XC8 compiler. Such names are generated by the MPLAB X Code Configurator and makes it easier to include code generated automatically by MCC.

Examples:
  Alternative name:       Existing name:
  PIE1bits.TMR1IE         TMR1IE
  TXSTAbits.TRMT          TRMT
  PIE1bits.RCIE           RCIE
  RCSTAbits.CREN          CREN
  INTCONbits.GIE          GIE
  OPTION_REGbits.nWPUEN   WPUEN_
  SCANTRIGbits.TSEL0      SCANTRIG_TSEL0

The new alternative names needs no further definitions. When two names <REGISTERNAME> and <BITNAME> are defined (in the device header file) and located at the same address, then the alternative name has the format:

  REGISTERNAMEbits.BITNAME

Restrictions: The alternative name only works for REGISTERNAME starting with a capital letter. The register and bit names has to be located at a fixed address using the format found in the device header files.

Version 3.8A released

Deep optimization of MOVLP

By using BRA instead of GOTO it is possible to remove more of the MOVLPs. Use of BRA is done automatically by the compiler before this optimization.

It is required to use optimization level 2 (option -z2) to perform the optimization.

  #pragma optimize 9:0    // disable optimization type 9
  #pragma optimize 9:1    // enable optimization type 9

Deep optimization of MOVLP is type 9 and is enabled by default.

Using optimization levels

The different optimization types are assigned to different optimization levels. All existing basic optimization types (1..8) are set to level 1. New optimization types are assigned higher levels. The initial optimization level is the level set at the start of compilation.

NOTE: the default initial optimization level is 1.

Optimization level 1 means that only the basic optimization is performed. The default initial optimization level may change in future releases.

The initial optimization level can be changed by option -z<N>, for example -z2 will set optimization level 2.

The current optimization level during compilation can be changed during compilation by #pragma optimize z<N>, but it is NOT possible to increase the current optimization level above the initial optimization level.

  #pragma optimize z2    // set optimization level 2
  #pragma optimize z1    // set optimization level 1 - basic types only
  #pragma optimize z0    // disable all optimization

  #pragma optimize zi    // restore to initial optimization level

Changing the optimization level makes it possible to enable and disable groups of optimization types.

All optimization types are enabled by default. The optimization level will not change the individual setting (enabled/disabled) of each optimization type. If an optimization type is disabled then the optimization level will not enable this optimization type. A specific optimization type is only performed if the optimization type is enabled individually AND enabled by the current optimization level.

New code level

The code generator is improved from time to time. The code level tells which code is generated. The code generator is different from code optimization. Different code is generated for each code level. There will be changes within each level for new versions.

Available code levels:

  code level=0 : original code generator
  code level=1 : improved code related to new enhanced core 14 instructions
  code level=2 : improved code for division and remainder/modulus

The new default is code level 2.

The code level can be changed by:

  Option -cl<N> where <N> is 0..2
  #pragma codeLevel <N>   // where <N> is 0..2
  #pragma codeLevel i     // restore initial code level

Option -cl<N> defines the highest level for the entire application. This level cannot be increased by #pragma codeLevel.

Emulating the FREE edition

Option -cfr will emulate operation of the FREE compiler edition with the same limitations on optimization, variable size and code generation.

Option -cfr+ is similar but ignores the variable size restrictions.

Macro identifying the number of banks

The compiler defines a macro that represent the number of banks used for GPR and SFR registers. This macro is suitable for conditional compilation. The number of banks depends on the core configuration of the device. The macro is defined in the beginning of compilation. Example:

  #if __BANKS__ == 64
   // device with more than 5k space for RAM/GPR and SFR
  #elif __BANKS__ == 32
   // device with around 2.5k space for RAM/GPR and SFR
  #elif __BANKS__ == 4
   // legacy device with 4 banks only
  #endif

Macro identifying the chip

The compiler defines a macro starting with "PIC" that identifies the device. The macro is defined in the beginning of compilation. The macro identifier is identical to the device identifier, for example "PIC16F18877". The device can also be identified by the established macro "_16F18877". Example usage:

  #if PIC16F18877 == 1  // alternative _16F18877 == 1
   // code and definitions specific for this device
  #endif

Version 3.8 released

Renewed header files

New header files are generated according to the INI and CFGDATA files found in the MPLAB X package and will now contain more bit names and alternative bit names.

Renewed utility application SETCC

SETCC version 2.0 will use INI and CFGDATA files as found in MPLAB X. The use of mpasmx INC and LKR files has been removed.

Version 3.7D released

Version 3.7C released

Version 3.7A released

Version 3.7 released

Utility application SETCC

SETCC is useful for:

  1. Generating device specific header files
  2. Setting config symbols for a device
  3. Compiling projects

Reasons for generating header files using SETCC:

  • predefined header files may not be ready yet for new devices
  • the number of register symbols can be selected
  • the bit name format can be selected

The device header files supplied with the compiler can still be used.

Header file Options:

  1. bit name format: REGISTERNAME_BITNAME
  2. bit name format: BITNAME - limited set only
  3. bit name format: combined BITNAME / REGISTERNAME_BITNAME

NOTE: The SETCC utility is only available for licensed editions.

Const data stored in dedicated functions for each table

The data type DataInW allows integer data that fits within an instruction word (12/14 bit) to be stored in const data tables that are mapped to dedicated functions containing data elements only (no code or return). Note that it is not possible to use DataInW outside the const table.

It is possible to read and assign the address of the const table, but without any operations. All access of data within this type of tables must be done by an application access function. It is not possible to use a table index read (dataTable[i]), fixed offset (dataTable[5]) or pointers.

 const DataInW dataTable[] = {
     1234,
     3456,
     0x3FFF,  // 14 bit core: max 14 bit (12 bit for 12 bit core)
     0,
 };

 uns8 getData( uns16 ix)
 {
     uns16 base = (uns16) dataTable;  // get the table start address
     base += ix;

     // NOTE: register names and access procedure are device dependent
     NVMADRL = base;         // LSB of address
     NVMADRH = base >> 8;    // MSB of address

     NVMREGS = 0; // Do not select Configuration Space
     RD = 1;      // Initiate read

     return NVMDATL;  // read LSB
 }
 ..
 uns16 ix16;
 uns8 x = getData(ix16);

 uns8 y = NVMDATH;  // read MSB

Version 3.6 released

Support for symbolic device configuration

The config settings can be defined using standard symbols for the actual device. Example usage:

 #pragma config <id> = <state> [, <id> = <state>]

 #pragma config FOSC = ECL  // ECL, External Clock
 #pragma config WDTE = SWDTEN
 #pragma config PWRTE = ON, CP = ON, WRT = ALL
 #pragma config BORV = 25

Option -VG or -Vg will list the available symbolic config settings at the end of the *.var file generated for the project. This list can be copied to a project C source file and modified to desired settings.

 -VG : list default config settings and alternatives
 -Vg : list config setting alternatives

The available config symbols are defined at at the end of the device header file according to the following format:

 #pragma config /<regNr> <value> <id> = <state>

The compiler supports both direct and symbolic setting of the device configuration (see CONFIG.TXT). It is NOT allowed to combine direct and symbolic config settings.

It is possible to disable the symbolic config definitions found in the header files for backward compatibility with the fixed config symbols in compiler versions older than version 3.6.

 -D_DISABLE_DYN_CONFIG   : command line option

Starting assembler when using an ASM file as input

The compiler will start an assembler when using an ASM file instead of a C file as input. The assembler has to be defined using the -x and -X options.

Version 3.5G released

Version 3.5F released

Version 3.5E released

Support for 64 RAM banks (4k RAM or more)

New enhanced 14 bit core devices containing 4k RAM (PIC16F18877/PIC18857) are using 64 RAM banks. The existing enhanced 14 bit core use 32 RAM banks which allows up to 2.5k RAM.

The binary format of the MOVLB instruction have changed for the new enhanced 14 bit core devices in order to support 64 RAM banks.

Multiple config register support

Up to 9 config registers are supported by the compiler.

 #pragma config reg1 = 0x1   // same as #pragma config = 0x1
 #pragma config reg2 = 0x1
 #pragma config reg3 = 0x1
 ..
 #pragma config reg9 = 0x1

Warning and error messages for certain pointer operations

Certain pointer operation will generate warnings. The warnings can be removed by adding a proper type cast. The first warning can be disabled by command line option -wx. The other two warnings be disabled by command line option -wz.

 // Suspicious pointer conversion   - different sign used
 // Incompatible pointer conversion - different size/type
 // Nonportable pointer conversion  - not a pointer/address

An error is generated when using a pointer as a table index.

Optimisation for overlapping bit parameters

Parameter transfer can be omitted for functions sharing overlapping bit parameters.

 bit sharedBitPar;
 bit func2( bit par @ sharedBitPar )
 { /*..*/ return Carry; }
 bit func1( bit par @ sharedBitPar )
 { /*..*/ return func2( par ); }

Optimisation of certain expressions

 uns8 a8, b8;
 uns16 u16;
 a8 = (a8 & 0xF) + 1;
 a8 = (b8 & 0x40) == 0;
 W = a8 / 4;  // 8,32,64,128
 W = a8 * 128;
 a8 = u16 / 16;
 a8 = !b8.3;
 *FSR0++ ^= W;
 W = u16 / 4;  // 8,16,32,64,128
 u8 = u16 / 8;  // 16,32,64
 a8 = (a8 & 0xF) + 1;
 a8 = (a8 | 0x7) - 1;
 a8 = (a8 | (c8 & 0xF)) + 1;
 a8 = (a8 | 7) + 7;
 a8 = (a8 & 0xF) << 1;
 a8 = (a8 ^ 0xF) * 8;
 u16 = (u16 + 1) | 0xC0;

Generating a HEX file with data only (no code)

It is possible to successfully compile a source file that contains data only. Typically the source code will contain #pragma cdata statements with FLASH or EEPROM data.

Syntax enhancements

 char *pi;
 struct stxx *pxx;
 pxx = (struct stxx *) pi;  // struct/union type cast     

UTF byte order mark in the start of a source file

The UTF-8 representation of the Byte Order Mark is the byte sequence 0xEF,0xBB,0xBF. This sequence is allowed in the start of a source file.

Version 3.5D released

COFF debugging file

Command line option -CF will generate a COFF file (*.cof) for debugging in the MPLAB X environment.

Version 3.5C released

Version 3.5B released

Version 3.5A released

Replacing GOTO by BRA

The new enhanced core 14 devices has a Branch Always instruction. Command line option -gb allows GOTO to be replaced by the BRA instruction when the destination is within range. The code size will not change. Note that the GOTO used at the startup vector and after terminating main will not be replaced.

The BRA instruction can be used in inline assembly also. The compiler will check that the destination is within range.

Version 3.5 released

Locating Const Data

The compiler will normally insert 'const' data at the start of each codepage (after the interrupt routine). The following pragma statement will allow 'const' data for the current codepage to be inserted between user functions, or at a specific address when using #pragma origin first. The current codepage can also be set by using #pragma codepage.

 #pragma insertConst     

Code generator improvements for Enhanced 14 bit core

Improvements are related to direct use of FSR0 and FSR1 registers using auto-increment/decrement or constant offset (-32..31):.

 uns8 aa;
 if (*FSR0++ == aa)  ..
 if (*--FSR1 >= aa)  ..
 if (*++FSR1 != *--FSR0) ..
 if (*++FSR1 < *FSR0--) ..
 if (FSR1[3] < aa) ..
 if (FSR0[1] == aa) ..
 FSR0[2] = aa;
 FSR0[-1] = FSR1[2];
 FSR0[-31] = FSR1[12] | aa;     

Version 3.4I released

Support for the new Enhanced 12 bit core (baseline)

NOTE: A full update agreement not expired earlier than November 2012 is required to get an update with enhanced 12 bit core support.

Version 3.4H released

Version 3.4E released

Version 3.4D released

Version 3.4C released

Automatic search in installed directory for include files

The compiler will automatically search in the installed directory for include files. This means that option -I"C:Program Files\bknd\CC5X" or similar is not required to include device header and math header files. The search in the installed directory is done after other directories specified using option -I have been searched.

Version 3.4B released

PIC1xLF and PIC1xF devices use same header file

The compiler will include the header file for the corresponding F device when working with a LF device. These header files are normally identical except for the device name. An option will disable this merging and allow a separate header file for the LF device:

  -csh : include separate chip header file for 'LF' devices

Warning for read-modify-write sequences on the same PORT

The compiler will check read-modify-write instruction sequences on the same PORT, and generate a warning if a failure may occur. Such sequences consist of a read-modify-write (or write) instruction immediate followed by a read-modify-write instruction on the same PORT. This may result in wrong output state on some PORT pins depending on CPU speed and capasitive load on the PORT pins. The problem (and warning) can be avoided by doing the last read-modify-write operation on the LATCH register instead of the PORT register (Enhanced 14 bit core devices have PORT latch registers). The warning can be removed by the following option:

  -wf : no warning for read-modify-write sequences on the same PORT

Version 3.4A released

Version 3.4 released

The STANDARD edition now supports 32 bit integers

Improved code generator

The code generator has been enhanced for all devices. This means faster and more compact code for 24 and 32 bit operations. It also means better code for signed right shifts and some other special cases.

Applications requiring compatibility with old compiler versions can use the following:

  -cl0 : option to use old code generator for whole application

 #pragma codeLevel 0
 // use old code generator in this region
 ..
 #pragma codeLevel 1     

NOTE: A full update agreement valid on the version 3.4 release date is required to get an update that will use the improved code generator.

Support for new Enhanced 14 bit Core

New devices with Enhanced 14 bit core allow up to 32k words of code, 4k RAM and SFR adressing, 16 level stack, linear RAM adressing, fast interrupt handling and several new instructions.

See file DEMO-ENH.C for syntax examples.

The symbol __EnhancedCore14__ is defined (equal to 1) when compiling code for devices using Enhanced Core 14.

 Symbol __CoreSet__ = 1410  : 14 bit enhanced core
                      1400  : 14 bit standard core
                      1200  : 12 bit core     

NOTE: A full update agreement not expired earlier than January 2009 is required to get an update with FULL enhanced 14 bit core support. A partial update agreement valid on the version 3.4 release date enables a limited update which will not use all new instructions.

New internal function offsetof( struct_type, struct_member)

Function offsetof() returns the offset to a structure member. The first argument must be a struct type, and the second a structure member. The function can also be used in a preprocessor expression.

 typedef struct sStx {
     char a;
     uns16 b;
 } Stx;

 x = offsetof( Stx, b);
 x = offsetof( struct sStx, a);
 x = offsetof( struct_x, member_n.sub2.q[3]);     

List file with no page formatting

Option -Ln will produce a list file with no page formatting.

Version 3.3H released

Support of the standard __LINE__ and __FILE__ macros

Simplified state definition for multitasking

Task states normally have to be enumerated from 1..N with no missing numbers in between. It is now possible to use an undefined symbol to represent the state without any state numbering conflicts. The compiler defines any unknown symbols and missing state numbers to the lowest unused state numbers. Defined state number can be mixed with unknown state numbers.

 enum { SA = 1, X_STATE = 3 };
 ..
 waitState(SA);        // defined state number (1)
 ..
 waitState(X_STATE);   // defined state number (3)
 ..
 waitState(ST_Z); // state defined by compiler (2)
 ..
 waitState();     // state defined by compiler (4)
 ..
 changeState(ST_Z);    // return to state ST_Z     

Alternative assignment of command line symbols

Symbols defined on the command line normally use '=' to separate the symbol and the symbol contents. It is now possible to use most ASCII token different from letters, numbers and '_' to mark the end of the symbol. This makes it easier to avoid command line interpretation conflicts. Examble:

 -DMY_SYMBOL:100
   is equivalent to:
 #define   MY_SYMBOL   100     

Version 3.3A released

Standard MPASM EQU symbols can define config settings

Complete example setup is found in file CONFIG.TXT.

 #pragma config = _PWRTE_ON & _WDT_ON & _LP_OSC
 #pragma config reg2 = _WRT_256 & _BOR21V     

Multiple include paths can be separated by semicolons

A single -I option may contain multiple include paths separated by semicolons (instead of using separate -I options).

 -Ic:\path\to\inc1;c:\path\to\inc2;\inc3;inc4     

Extended search for include files

The compiler can search more directories for include files when using option -cif. Step 3) and 4) are the default search for include files that are performed without this option.

  1. in the directory that contains the file being compiled
  2. if the file being compiled was included from another file, then the directory containing this file is searched. This is repeated until the directory of the initial (root) file has been searched.
  3. in current directory (where the compiler was started). This step is NOT performed when using #include <file> or option -cxc.
  4. in include directories defined by the -I option

Multiline comment allowed in #define

A comment after #define may end at a following line:

 #define M1  1  /* This comment
                   is legal */     

Version 3.3 released

Stack allocation alternatives

The stack for local variables, parameters and temporary variables is normally allocated separately in each bank and the shared RAM area. The bank is normally defined the same way as global variables through #pragma rambank or bank type modifiers. This makes it possible to split the stack into several independent stacks. Using a single stack is normally recommended, but sometimes this is not possible when the stack size is too large.

The following pragma will define a single main stack. The main stack is not an additional stack, but tells the compiler where the main stack is located (which bank).

 #pragma mainStack 3 @ 0x20     

Using this pragma means that local variables, parameters and temporary variables of size 3 bytes and larger (including tables and structures) will be stored in a single stack allocated no lower than address 0x20. Smaller variables and variables with a bank modifier will be stored according to the default/other rules. Using size 0 means all variables including bit variables.

Note that the bank defined by #pragma rambank is ignored for variables stored in the main stack. Address ranging from 0x20 to 0x6F/0x7F are equivalent to the bank0 type modifier.

In some cases it will be efficient to use shared RAM or a specific bank for local variables up to a certain size. This is possible by using the following pragma:

 #pragma minorStack 2 @ 0x70     

In this case, local variables, parameters and temporary variables up to 2 bytes will be put in shared RAM from address 0x70 and upward. Larger variables and variables with a bank modifier will be stored according to the default/other rules. Using size 0 means bit variables only. This pragma can be used in combination with the main stack. The variable size defined by the minor stack have priority over the main stack.

The most efficient RAM usage is to use a single stack. Separation into different stacks increase total RAM usage, and should be avoided if possible.

Strongly improved SQRT rutine

The new square root routine developed by Jim van Zee, Seattle, executes fast (1/3 of the time) and is small (save more than 50 % code). An additional benefit is improved accuracy. The routine is available for 24 and 32 bit floating point. The new routine is automatically used when including "math24lb.h" or "math32lb.h".

Address sorting in the HEX file

The records in the HEX file are sorted according to the address. Option -chu will disable this sorting for backward compatibility with old compiler versions.

Option for chip redefinition

MPLAB supplies the option -p<chip> automatically. Sometimes this is not desirable. The new option -p- will clear any preceding -p<chip> to allow chip redefinition, either by a new -p<chip> or a #pragma chip statement.

Version 3.2N released

Macros can be used in #include files

The following examples show the possibilities. Note that this is not standard C.

 #include "file1" ".h" 
 #define MAC1 "c:\project\"
 #include MAC1 "file2.h"
 #define MAC2 MAC1 ".h"
 #include MAC2
 #define MAC3 <file3.h>
 #include MAC3     

RULES:

  1. Strings using "" can be splitted, but not strings using <>
  2. Only the first partial string can be a macro
  3. Nested macros is possible
  4. Only one macro at each level is possible

Support of CCINC and CCHOME

Environment variables can be used to define include folders and primary folder.

Variable CCINC is an alternative to the -I<path> option. The compiler will only read this variable (or specified variable) when using the following command line option:

 -li  : read default environment variable CCINC
 -li<ENVI> : read specific environment variable     

Variable CCHOME can be used to define the primary folder during compilation. The compiler will only read this variable (or specified variable) when using the following command line option:

 -lh  : read default environment variable CCHOME
 -lh<ENVP> : read specific environment variable     

Version 3.2K released

Version 3.2I released

New type modifier 'shadowDef'

The 'shadowDef' type modifier allow local and global variables and function parameters to be assigned to specific addresses without affecting normal variable allocation. The compiler will ignore the presence of these variables when allocating global and local variable space.

 shadowDef char gx70 @ 0x70;  // global or local     

The above definition allow location 0x70 to be inspected and modified through variable 'gx70'.

Assigning function parameters to specific locations

Function parameters can be assigned to addresses. No other variables will be assigned by the compiler to these locations. Such manual allocation can be useful when reusing RAM locations manually.

 void write(char addr @ 0x70, char value @ 0x71)
 { .. }     

This syntax is also possible on function prototypes.

main() can reside in any codepage

It is possible to locate main() in any codepage if the reset vector is omitted. This is done by a pragma statement.

 #pragma resetVector -      

Proper startup code must be inserted manually when removing the automatic reset vector, for example by cdata[] statements (cdata.txt).

Version 3.2G released

Support for __config and __idlocs

The compiler will use __config and __idlocs in the generated assembly file when #pragma config is used in the C source. The old assembly format is still available by using the command line option -cfc.

Macros __DATE__ and __TIME__

Macros for date and time are defined when compilation starts.

 Macro      Format          Example
 __TIME__   HOUR:MIN:SEC    "23:59:59"
 __DATE__   MONTH DAY YEAR  "Jan 1 2005"
 __DATE2__  DAY MONTH YEAR  " 1 Jan 2005"     

Version 3.2F released

Custom warnings and simple messages

A custom warning or a simple message can be printed in the compiler output and to the .occ file. Option -S will suppress this. "warning" and "message" are not reserved keywords. Note that these directives are not standard C.

 #message This is message 1
 #message This is message 2
 #warning This is a warning     

The following output is produced:

 Message: This is message 1
 Message: This is message 2
 Warning test.c 7: This is a warning     

Version 3.2A released

Functions shared between independent call trees

An error message is normally printed when the compiler detects functions that are called both from main() and during interrupt processing if this function contains local variables or parameters. This also applies to math library calls and const access functions. The reason for the error is that local variables are allocated statically and may be overwritten if the routine is interrupted and then called during interrupt processing.

The error message can be changed to a warning by the following pragma statement. Note that this means that local variable and parameter overwriting must be avoided by careful code writing.

 #pragma sharedAllocation     

Improved inline assembly

The following address operations is possible when the variable/struct/array set to a fixed address.

 char tab[5] @ 0x110;
 struct { char x; char y; } stx @ 0x120;
 #asm
 MOVLW tab
 MOVLW &tab[1]
 MOVLW LOW &tab[2]
 MOVLW HIGH &tab[2]
 MOVLW UPPER &tab[2]
 MOVLW HIGH (&tab[2] + 2)
 MOVLW HIGH (&stx.y)
 MOVLW &stx.y
 MOVLW &STATUS
 #endasm     

Output from preprocessor

The compiler will write the output from the preprocessor to a file (.CPR) when using the -B command line option. Preprocessor directives are either removed or simplified. Macro identifiers are replaced by the macro contents.

 -B[pims] : write preprocessor output to <src>.cpr
    p : partial preprocessing
    i : .., do not include files
    m : .., modify symbols
    s : .., modify strings     

When using the alternative preprocessing formats (-Bpims), compilation will stop after preprocessing.

Version 3.2 released

New math operator

Applies to 8*8 signed multiplication:

 int 8 a, b;
 int16 r = (int16)a * b;     

The following operator is added to math16.h, math24.h and math32.h:

 int16 operator* _multS8x8( int8 arg1, int8 arg2);     

Direct coded instructions

The file "hexcodes.h" contains C macros that allow direct coding of instructions.

Note that direct coded instructions are different from inline assembly seen from the compiler. The compiler will view the instruction codes as values only and not as instructions. All high level properties are lost. The compiler will reset optimization, bank updating, etc. after a DW statement.

Example usage:

 #include "hexcodes.h"
 ..
 // 1. In DW statements:
 #asm
 DW __DECF(__FSR,__F) // Decrement FSR
 DW __BCF(__STATUS,__Carry) // Clear Carry bit
 DW __GOTO(0) // Goto address 0
 #endasm
 ..
 // 2. In cdata statements:
 #pragma cdata[1] = __GOTO(0x3FF)     

RAM bank update settings

#pragma updateBank can be used to instruct the bank update algorithm to do certain selections. These statements can only be used inside the functions:

 #pragma updateBank entry = 0
 /* The 'entry' bank force the bank bits to be set
 to a certain value when calling this function */

 #pragma updateBank exit = 1
 /* The 'exit' bank force the bank bits to be set 
 to a certain value at return from this function */

 #pragma updateBank default = 0
 /* The 'default' bank is used by the compiler at
 loops and labels when the algorithm give up
 finding the optimal choice */     

Origin alignment

It is possible to use #pragma origin to ensure that a computed goto inside a function does not cross a 256 word address boundary. However, this may require many changes during program development. An alternative is to use #pragma alignLsbOrigin to automatically align the least significant byte of the origin address. Note that this alignment is not possible when using relocatable assembly, and also that it does not apply to the 12 bit core.

Example: A function contain a computed goto. After inspecting the generated list file, there are 16 instructions between the function start and the first destination address (offset 0) right after the ADDWF PCL,0 instruction that perform the computed goto. The last destination address (offset 10) resides 10 instructions after the first destination. A fast a compact computed goto requires that the first and last destination resides on the same "byte page" (i.e. (address & 0xFF00) are identical for the two addresses). This is achieved with the statement:

 #pragma alignLsbOrigin -16 to 255 - 10 - 16     

The alignment pragma statement is not critical. The compiler will generate an error (option -GS) or a warning (-GW) if the computed goto cross a boundary because of a wrong alignment. An easier approach is to align the LSB to a certain value (as long as program size is not critical).

 #pragma alignLsbOrigin 0 // align on LSB = 0
 #pragma alignLsbOrigin 0 to 190 // [-255 .. 255]
 #pragma alignLsbOrigin -100 to 10     

Easier storing of unpacked strings in EEPROM

The compiler will normally store cdata strings as 2*7 bits packed data. This is now selectable.

 // Store strings packed by default
 #pragma cdata[0x800] = "Hello world!\0"

 #pragma packedCdataStrings 0
 // Store following strings unpacked
 #pragma cdata[0x2100] = "Hello world!\0"
 #pragma cdata[] = 1, 0x80
 // Next statement is legal, but EEPROM use 8 bit
 //#pragma cdata[] = 0x3FFF

 #pragma packedCdataStrings 1
 // Store remaining strings packed     

Improved const data initialization

Floating point constant expressions.

Complex address calculations.

Enum-symbols allowed.

Extra config register supported

Enabled in the header file (#pragma config_reg2 0x2008).

 #pragma config reg2 = 0x1 | 0x2     

Version 3.1J released

Improved integer math libraries

Improved 16 * 16 bit multiplication.

Version 3.1I released

Switch statements of 16, 24 and 32 bit

The switch statement now supports variables up to 32 bit. The generated code is more compact and executes faster than the equivalent 'if - else if' chain.

Version 3.1H released

Macro stringification and concatenation

The concatenation operator ## allows tokens to be merged while expanding macros. The stringification operator # allows a macro argument to be converted into a string constant.

Version 3.1G released

Syntax improvements

Multiple assignment:

 a = b = c;     

Allowing the increment operator on the left side of a statement:

 ++i;
 --x;     

Improved "increment" part of the 'for' statement :

 for (i=0; i<5; a.b[x]+=2) ..     

Better paranthesis support :

 *(p)
 (p)[0]
 &(l.a)     

Better 'enum' support :

 typedef enum ..
 enum con { Read_A, .. };
 enum con mm;
 mm = Read_A;     

Placing the interrupt routine anywhere

The interrupt routine normally have to reside on address 4. The following pragma statement will allow the interrupt routine to be placed anywhere. Note that the compiler will NOT generate the link from address 4 to the interrupt routine automatically.

 #pragma unlockISR     

Printing key info in the assembly file

The compiler will print info at the end of the assembly file. Total code size, code size on each code page, maximum call level, RAM usage. In addition, the size of each function is printed. Command line option -Au removes this information.

Version 3.1F released

Detailed multiline macro expansion in assembly file

Single lines from multiline macros are printed in the generated assembly file when using command line option -AR. This is sometimes useful to improve readability when expanding very long macros.

Recursive printing of errors in macros

If there is a syntax error in a defined macro, then it may be difficult to decide what the problem actually is. This is improved by printing extra error messages which points to the macro definition, and doing this recursively when expanding nested macros.

Automatic incrementing version number on file

CC5X is able to automatically increment one or more version numbers for each compilation. Syntax supported:

1. Option : -ver#verfile.c

 #include "verfile.c" // or <verfile.c>     

2. Option : -ver

 #pragma versionFile // next include is version file
 #include "verfile.c" // or <verfile.c>     

3. Option : -ver

 #pragma versionFile "verfile.c" // or <verfile.c>     

Note that the command line option is required to make this increment happen. It is the decimal number found at end of the included file that is incremented. The updated file is written back before the file is compiled. No special syntax is assumed in the version file. Suggestions:

 #define MY_VERSION 20
 #define VER_STRING "1.02.0005"
 /* VERSION : 01110 */     

If the decimal number is 99, then the new number will be 100 and the file length increase by 1. If the number is 099, then the file length remains the same. A version file should not be too large (up to 20k), otherwise an error is printed.

Formats 2 and 3 above allows more than one version file. It is recommended to use conditional compilation to manage several editions of the same program.

Version 3.1E released

Detection of REGISTER saving and restoring during interrupt

CC5X will AUTOMATICALLY check that the registers W, STATUS, PCLATH and FSR are saved and restored during interrupt.

The details about this is found in file 'int16Cxx.h'.

The error and warning messages printed can be removed:

 #pragma interruptSaveCheck n // no warning or error
 #pragma interruptSaveCheck w // warning only
 #pragma interruptSaveCheck e // error + warning     

Version 3.1D released

Better variable overlapping

Variables can overlap parts of another variable, table or structure. Multiple levels of overlapping is allowed.

 char aa @ ttb[2]; // char ttb[10];
 bit ab @ aa.7; // a second level of overlapping
 bit bb @ ttb[1].1;
 size2 char *cc @ da.a; // 'da' is a struct
 char dd[3] @ da.sloi[1].pi.ncup;
 uns16 ee @ fx.mid16; // float32 fx;
 TypeX ii @ tab; // TypeX is a typedef struct     

Using expressions to define addresses

An expression can now define the address of a variable. This makes it easier to move a collection of variables.

 char tty @ (50+1-1+2);
 bit tt1 @ (50+1-1+2+1).3;
 bit tt2 @ (50+1-1+2+1).BX1; //enum { .., BX1, .. };     

Address operations

The logic for checking address operations is enhanced. The supported operations are:

 ADR + EXPRESSION (VARIABLE/CONST)
 ADR - EXPRESSION (VARIABLE/CONST)
 ADR & 0xFF; // LSB : least significant 8 bits
 ADR % 256; // LSB : least significant 8 bits
 ADR >> 8; // MSB : most significant bit(s)
 ADR / 256; // MSB : most significant bit(s)     

Example:

 FSR = &table[3] & 0xFF;
 IRP = &table[3]>>8;//on devices using 9 bit address     

A warning is printed when using other address operations (for example &p | 3). This warning is changed to an error when using relocatable assembly (option -r).

Combining inline integer math and library calls

It is possible to force the compiler to generate inline integer math code after a math library is included. This may be useful when speed is critical or in the interrupt service routine. Functions with parameters or local variables are not reentrant because local variables are mapped to global addresses, and therefore the compiler will not allow calls from both main and the interrupt service routine to the same function.

 uns16 a, b, c;
 ..
 a = b * c; // inline code is generated
 ..
 #include "math16.h"
 ..
 a = b * c; // math library function is called
 ..
 #pragma inlineMath 1
 a = b * c; // inline code is generated
 #pragma inlineMath 0
 ..
 a = b * c; // math library function is called     

Inline type modifier on math operations

It is possible to combine inline integer math and math library functions without making a special purpose math library. This is done by stating that the selected operations are inline BEFORE the standard math library is included. It is optimal to use inline code when there is only one operation of a certain type.

 inline uns24 operator * (uns24 arg1, uns24 arg2);
 #include "math24.h"     

The math prototypes are found in the beginning of the standard math libraries. Just remember to remove the operator name before adding the inline type modifier.

A warning is printed when there is ONE call to a unsigned integer math library function. The warning can be disabled by the -wm command line option.

NOTE that the inline type modifier is currently IGNORED, except for the math operations.

Detection of multiple inline math integer operations

The compiler will print a warning when detecting more than one inline math integer operation of the same type. Including a math library will save code, but execute slightly slower. Note that assembly code inspection and type casts are sometimes needed to reduce the number of library functions inserted.

The warning can be disabled by the -wi command line option.

Reading program memory on more devices

The compiler will now read program memory directly on devices having the predefined registers:

 PMDATA,PMADR,PMDATH,PMADRH :16C925/926/F73/74/76/77
 PMDATL,PMADRL,PMDATH,PMADRH :16C717/770/771/781/782     

The compiler will use computed goto (more code, but faster) instead of direct program memory reading when using:

 #pragma wideConstData 8192     

Version 3.1C released

Cdata outside legal program and eeprom space is disabled

 CODE: 0x0000 - upper program limit
 EEPROM: 0x2100 - 0x21FF : eeprom data space     

The error message can be changed to a warning by using the -cd command line option.

End line