STxP70/STHORM/P2012 - ST's secret microcontroller

ST has this "Time-of-Flight 8x8 multizone ranging sensor with wide field of view"... thing, called the VL53L5CX.

There's a line in the datasheet, under the Features heading - "Low-power microcontroller running Firmware". Ignoring that "having firmware" is apparently a cool enough feature to bother listing in your datasheet, it means there's some kind of processor inside this thing. So, uh, we need its firmware. Not the firmware that interfaces with the sensor, but the firmware that runs on the sensor itself. Why? Because we do.

If we download the "Ultra Lite Driver", and take a peek at the initialisation stuff within VL53L5CX_ULD_API/src/vl53l5cx_api.c:

uint8_t vl53l5cx_init(
        VL53L5CX_Configuration      *p_dev)
// ...
    /* Enable FW access */
    status |= WrByte(&(p_dev->platform), 0x03, 0x0D);
    status |= WrByte(&(p_dev->platform), 0x7fff, 0x01);
    status |= _vl53l5cx_poll_for_answer(p_dev, 1, 0, 0x21, 0x10, 0x10);
    status |= WrByte(&(p_dev->platform), 0x7fff, 0x00);
// ...
    /* Download FW into VL53L5 */
    status |= WrByte(&(p_dev->platform), 0x7fff, 0x09);
    status |= WrMulti(&(p_dev->platform),0,
    status |= WrByte(&(p_dev->platform), 0x7fff, 0x0a);
    status |= WrMulti(&(p_dev->platform),0,
    status |= WrByte(&(p_dev->platform), 0x7fff, 0x0b);
    status |= WrMulti(&(p_dev->platform),0,
    status |= WrByte(&(p_dev->platform), 0x7fff, 0x01);
// ...

πŸΆπŸ’­ πŸ₯ΊπŸ₯ΊπŸ’•

So the driver definitely contains some of the sensor's firmware. That VL53L5CX_FIRMWARE array, from VL53L5CX_ULD_API/inc/vl53l5cx_buffers.h, is just a huge array of bytes:

 * @brief This buffer contains the VL53L5CX firmware (MM1.3)

const uint8_t VL53L5CX_FIRMWARE[] = {

 0xe0, 0x04, 0x07, 0x68,
 0xe0, 0x04, 0x0f, 0x28,
 0xe0, 0x04, 0x09, 0x68,
 0xe0, 0x64, 0x1a, 0xc8,
// ...

With some vim booping (basically %s%\(0x\|,\)%%g to remove all 0xes and ,s), we can strip all the C flourish away and end up with some hex data - e0 04 07 68 on the first line, e0 04 0f 28 on the next, and so on - that we can pipe into xxd -r -p to turn it back into binary data.

Now that we have that, well:

$ binwalk firmware.bin


$ python ../_tools/cpu_rec/ firmware.bin 
    full(0x15000)       None
    chunk(0x400;2)      NDS32

partially reformatted, and the annoying warning cpu_rec always prints removed

Looks like we're on our own. That NDS32 chunk is most likely a red herring.

Who's that CPU?

There's a cute string in the initialisation code - enable host access to go1. It sounds like the kind of string that might appear next to some other firmware loading code for another device using the same or similar CPU, that could shed more light on the whole situation. It's also unique enough that we're unlikely to find unrelated info. We can totally use it to go hunting for more relevant code.

GitHub immediately shows us a kernel driver for the VL53L5 and a file called stmvl53l5_load_fw.c. It's got a lovely line at the top, which points us to the associated header file:

// from stmvl53l5_load_fw.c
const uint8_t _fw_buffer[] = EWOKMZ_STXP70_TCPM_RAM_FULL;
// from stmvl53l5_load_fw.h
    0xe0, 0x00, 0x03, 0x08, \
    0xe0, 0x00, 0x0a, 0xc8, \
    0xe0, 0x00, 0x05, 0x08, \
    0xe0, 0x64, 0x33, 0xa8, \
    0xe0, 0x00, 0x0a, 0x88, \
// ...

sickos_yes.jpg puppys_yes.jpg

The FW looks quite similar, but the name of the preprocessor constant sheds a ton of light on the situation. EWOKMZ - bad start, not a clue (searching now, seems like the codename for the VL53L5?). STXP70 - hey, that sounds like a CPU name. TCPM - maybe tightly-coupled program memory? RAM_FULL - it's probably a complete copy of what needs to end up in RAM.

STXP70: so starts the saga

The STxP70, also known as the xP70, or the STxP70-v3, -v4 and -v4B for some specific variants, is. Something. Some kind of CPU core.

ST seems to have let a lot more slip about what this core is in the past, but a lot of it has long since disappeared from the internet.

from a slideshow, but it has spoilers so don't look yet

As far as I can tell, the STxP70 is a 32-bit RISC core developed by ST. It has a 7-stage pipeline, is dual issue in certain configurations (executes two instructions at once), and is highly extensible - supporting ISA extensions through additional hardware tacked onto the core.

ST seems to have used (or still use?) the STxP70 as a general-purpose core to throw in devices. I think I've seen references to it in code as far back as 2008, so it's certainly not new. So far, I've found the core in this ranging sensor, in an image signal processor (namely the ISP8500, which only exists within some specific ST SoCs?), in a DAB SoC as a DSP, as a management core doing DRAM init in that ST SoC (for set-top boxes and stuff, I think?), in an ST display controller (yet again in one of these set-top box SoCs), and probably a billion other places I haven't found.

I've found a tiny bit about the instruction set and its encoding. We have a crt0.s, ish, and some other support stuff also written in assembly. Those (plus some of the limited stuff from docs before) also tell us we have predicated instruction execution (g0? and other numbered predicate registers written before instructions) and apparently even hardware loop counters, although the block diagram above makes that seem like an optional feature. Immediates can be loaded into registers with make, to load one half, and more for the other half (it's not clear if more loads the top half, or shifts the reg then loads the bottom half again). We've also got a single screenshot from the STWorkbench IDE that shows some instruction encodings - e.g. e0 40 00 15 for G7? MAKE R0, 0x0 (that e0 looks quite similar to how our sensor firmware began).

P2012: the saga continues

P2012, also known as Platform 2012, sometimes Platform P2012, and renamed at some point to STHORM (also written as SThorm) is a combination of a variable number of STxP70 cores, in a multi-core processing arrangement. Either managed by one or two ARM cores, or yet another STxP70 core, it was intended to make some kind of splash in the space between CPU/GPGPU processing and custom silicon/gateware (note: this is what every project in this space tries to do). It seems to have been developed in conjunction with CEA, which to be honest might explain a bit about the secrecy.

The P2012/STHORM seems to have got a lot of attention in academia. For some reason. A lot of stuff about OpenCL/OpenMP. Google Scholar lists a loooot of papers. It also seems to have maybe made it into, again, one of ST's STB SoCs.

The folks behind "BarbequeRTRM" (run-time resource manager) seem to have got their hands on a STHORM dev board (audio warning), which has the STHORM chip itself, a Zynq and way too many DC-DCs. That board in the video is also sitting atop some documentation I really want. But I still want the board.

At first I thought the Zynq was running the STHORM as gateware, but a slideshow from which the below slide is taken seems to indicate otherwise - the STHORM did actually get taped out.

That also explains this lovely diagram - the host is the Zynq, with its dual A9 cores.

Loose ends

Where can we get the STxP70 toolset?

It seems like this was available from ST at some point. It's a standard set of compilers and tools (the typical GNU-y collection), and the "how to build and test embedded software" application note (AN3505) and compiler manual (UM1237) give some idea of the supplied tools. There's, at minimum, st70xpcc (with a potential link to the Open64 toolchain), stxp70-ld, and stxp70-as, then some additional tooling for running and debugging called sxrun (simulator) and sxgdb. An older compiler called sxcc is mentioned, which the compiler manual says there's apparently compatibility with. There's the standard litany of stxp70-readelf and stxp70-objdump stuff too.

I'm not sure why it's called a "toolset" but it appears to integrate tightly with STWorkbench.

Some folder names I've come across so far look like STxP70_Toolset_4_1_0_Patched and STxP70_Toolset_2011.2_Patched from a Makefile on GitHub. The compiler manual says there's at minimum also 2012.1, 2012.1 patch 001, 2012.2, 2012.2 Update 01, and 2013.1 versions.

Where are the other manuals referenced in AN3505?

There's mention of some documents I haven't been able to find:

From AN3505:

  • STxP70-4.4.0 core and instruction set architecture reference manual (Doc ID 023738)
  • STxP70 professional toolset user manual (7833754)
  • STxP70-4 utilities reference manual (8210925)

From UM1237, but not in AN3505:

  • Advanced debugging with the STxP70-4 instruction-accurate simulator (Doc ID 024404)
  • Building STxP70 libraries application note (8226669)

From the BarbequeRTRM video:

  • "STHORM evaluation kit"

Where are they? Were they ever publicly available? Are they hiding on ST's website somewhere? Why are some of the documents on ST's site, and indexed, but these aren't? Can I please please please have the ISA reference manual? Please? πŸ₯Ί

Where can we get the P2012 SDK?

Also seems like it was available at some point, through "Minalogic" at This is since gone, but even in the day required signing an NDA and having a confirmed account to download.

Some relevant filenames for the P2012 SDK include from dmmlib's P2012 SDK build instructions.

What happened to P2012/STHORM?

It seems like there was a flurry of academic research between (maybe?) 2010 and up to even 2016. But somehow, despite all that, it seems not to exist outside of academia. Did it die? Commercial product never released? Commercial product released, but kept super secret? ST just enjoying the free work it's getting through academia? All the chips burnt up when the thermal management research went nowhere?

That's about it

I'd be here for weeks re-finding information if I tried to make this comprehensive. If you've found something, or have any questions, hit me up on Twitter.

You might also be interested in:

See all posts