Pointer-less C Compiler For PIC18Fxxxx MCUs - PLCC18

by Mengjin Su 

(originally published on "Embedded Systems Design, pp16~21, Sept., 2006. Vol. 19, Num. 9")

 

PLCC18 v1.00, implemented in 2007, is a newer version of PLC compiler which has been re-written since PLCC18 v0.4x.  It does not only have fixed a lot of bugs, but also has some improvements and grammar definition changes. Together with the compiler, it comes with the assembler (AS18) and a linker (LK18). With this change, the intermediate code, generated after assembling, is highly dynamic and locatable.  Moreover, PLCC18 v1.00 and higher can support recursive function call, even in PIC18Fxxxx legacy instruction mode! 

 

Why Pointer-less C

Frankly, 'pointer', as well as its related operations, is one of the most important features in C. It brings a tremendous efficiency and power to the language. But on the other side, C programmers, especially those beginners, sometimes complain about the ambiguity and the confusing using pointer in their programming. Today, a lot of MCUs used in embedded applications are in Harvard architecture that allocates ROM and RAM into two separate spaces. Each one needs to be accessed using different scheme or instructions (e.g. all the MCU products from Microchip are in this case). So the standard C pointer and its grammar notations may or may not work.

 

Pointer-less, Under the hood

PLCC uses different rules or syntax to do the same thing as that in standard C. In PLCC, only those basic data types exist: char, int and long (currently, 'float' data type has not been implemented in PLCC18).  The following tables illustrate how PLCC works to access the memory:

                  basic operations:

Standard 'C' Pointer-less 'C'

 

    

    char *p; /* declare a char's pointer */

  int *ip; /* declare a int's pointer */

 

     /* declare an integer that will hold an address */

      int p, ip;

    *p = 10;

  *ip = 1000;

 

    (p, char) = 10;

  (ip, int) = 1000;

 

    *p++ = 10;

  *ip-- = 1000;

 

    (p++, char) = 10;

  (ip--, int) = 1000;

 

    /* how to access the data in ROM? */

    if ( *((const char *)p) > 10 )

           p++; 

 

     /* specify the operation explicitly */ 

   if ( (p, const char) > 10 )

             p++;

 

 

                  'struct' and 'union' operations:

Standard 'C' Pointer-less 'C'
 

    /* define a struct */

    struct my_data {

       char a, b,

       int x, y;

  };

  struct my_data DATA;

  

    /* define a struct */

    struct my_data {

       char a, b,

       int x, y;

  };

  struct my_data DATA;

  struct my_data *p = &DATA;

    p->a = 10;

 

  int p = &DATA;

    (p, struct my_data).a = 10;

 

 

About PLCC18

PLCC18 is a small, efficient and easy to use compiler that supports PIC18Fxxxx series MCUs from Microchip. It works on both Windows and Linux platforms, under terminal/console mode. For convenience, we still use '.c' as extension for source files.

At present, only char(8-bit) int(16-bit) and long(32-bit) basic data types are supported (float might be supported in future). All basic arithmetic operations ('+', '-', '*', '/', '%') and logical operations ('&', '|', '^') are supported.  Plus, in-line assembly code insertion is allowed.  And the following pre-processors are accepted:

          #if  expression

          #else

          #endif

          #ifdef  symbol

          #ifndef symbol

          #pragma symbol   [expression]

          #asm

          #endasm

          #define symbol   expression

          #define  symbol(arg1, arg2, ...)   expression

 

No function recursive calling allowed in version PLCC18 v0.4x! (will be supported in higher version for those PIC devices with extended instruction set)

NOTE: PLCC18 v1.00 adds 'short' as the 24-bit integer type.

 

[1] Install the compiler

Unzip and extract all file, and then put them into a folder (e.g. PLCC). And then put the path into the environment, like

C:>\set path=%path%;C:\PLCC

[NOTE, you can make batch file (filename with extension '.bat') to set the path].

In this folder, you should see following files:

            plcc18.exe      - PLCC compiler

            as18.exe           - PIC18 assembler/linker

            lk18.exe           - PIC18 assembler/linker

            /lib                     - library folder (legacy instruction mode)

            /xlib                  - library folder (extended instruction mode)

            /include           - header files holder

 

[2] Compiling command:

   plcc18  <options>  filename1.c filename2.c ...

After compiling, if no error detected, assembly code(file) will be generated for each source file, ended with '.s'. The assembly code is very readable, and you can check what result exactly is.

where the options are:

        -L                                                generate assembly code in LIB mode

        -s                                                short jump instruction needed (default = long jump instruction)

        -Dsymbol<=xxxx>                      define symbol (with or without value)

 

[3] Assembling and linking

  p18asm <options> filename1.s  filename2.s  ...

where the options are:

      -device_name(mandatory)            specify PIC device (for example:   -pic18f452)

      -code=xxxx                                    code start address (default = 0x0000), no space allowed

      -data=xxxx                                     RAM data start address (default = 0x0002)

      -sp=xxxx                                        specify stack pointer initial value.

 

[4] Resources used by Compiler

PLCC18 will use following registers for compilation:

WREG PRODL PRODH FSR0L FSR0H FSR1L FSR1H FSR2L FSR2H TABLAT TBLPTRL TBLPTRH TBLPTRU STATUS BSR

Users should pay great attention when accessing any of those register in the code.

Further more, RAM location 0x0000 and 0x0001 (first two locations in bank0) are reserved for holding function return value (lower 16 bits). User should never use these location for any purpose. Index registers are used by compiler for index addressing. Among them FSR0L and FSR0H are use as software stack pointer. FSR1L, FSR1H, FSR2L and FSR2H are used for temporary storage dynamically*. BSR is cleared at power-on reset, and should never be modified afterwards.

(NOTE*: PICC18 version 0.5x or higher will use FSR2L and FSR2H as the software stack pointer)

 

[5] Download PLCC18

Click here to get PLCC18 v0.43. You can download and distribute it freely. Suggestions and comments are very welcome and can be sent to 'mengjins@hotmail.com'!