/lcc

The lcc retargetable ANSI C compiler

Primary LanguageC

What is ulpcc?

A C compiler targeting the ULP coprocessor on the ESP32 chip. It is based on the lcc compiler written by David Hanson and Chris Fraser. The code-generator for the ULP was written by Jason Fuller (me), and all bugs are mine.

Installation on Windows

  1. Download https://github.com/jasonful/lcc/raw/master/ulpcc.zip and extract to a directory of your choosing
  2. set the ULPCCDIR environment variable to the directory you extracted to.
  3. set IDF_PATH to where you installed the ESP IDF. (If you do not have it installed on your Windows machine, install it from here.)
  4. set PATH=%PATH%;%ULPCCDIR%\bin

Installation on Linux (tested on Ubuntu 20.04)

  1. cd ~
  2. git clone https://github.com/jasonful/lcc.git
  3. cd lcc
  4. source ~/lcc/ulpcc/doc/lccenv.sh
  5. buildlcc

Usage

  1. ulpcc foo.c will generate foo.S
  2. Build foo.S as you normally would a hand-written .S file.
  3. Globals in foo.c are exported with a ulp_ prefix just like .globals in a foo.S.

Not supported:

  1. Floating point
  2. Signed arithmetic. Despite what some parts of the documentation may imply, the ULP coprocessor has no support for signed arithmetic.
    This means you should always use unsigned int (or unsigned) instead of int.
  3. Division, multiplication, mod
  4. Function calls. Without a stack pointer, and only having 4 registers to play with, implementing this will take some thought. For now, hopefully this won't be a problem since most ULP programs are pretty short.
  5. Strings. The ULP coprocessor cannot access individual bytes.
  6. Arrays of structures. Calculating offsets requires multiplication, which is not supported.

Pseudo-functions

You can call the following ULP instructions as if they were functions: adc, halt, i2c_rd, i2c_wr, reg_rd, reg_wr, sleep, tsens, wait, wake.

Pseudo-functions that take parameters must take constants (not expressions) because the machine instructions take constants.

See %ULPCCDIR%\inc\ulp_c.h for details.

You can also call the pseudo-function include with a numeric argument. For example: include (1); will generate .include "1.S" in the .S file, allowing you to include assembly code from other files.

Notes:

  1. The compiler automatically inserts a halt at the end of entry().
  2. When something is not supported, I try to generate a friendly error message in the .S file.
  3. If you get an error like ulp_main.elf section '.text' will not fit in region 'ram' you will need to increase the space reserved for ULP code by modifying CONFIG_ULP_COPROC_RESERVE_MEM in your sdkconfig file. I believe the max is 8192.

Bugs

Report bugs to https://github.com/jasonful/lcc/issues