TRIGGER WARNING: The following content may harm the sensibilities of those who hate GOTO.
The reprint_cb() is a state machine that interprets a format string and outputs characters based on its current state. It is natural in its control flow that from a single dispatch point, the correct code segment is executed to say, output a numeric digit or bitfield. Typically, state machines are implemented with an integer representing the state and a corresponding switch statement that peforms the dispatch.
On embedded systems this wastes space and time. switch() statements entail a lookup table at best, and a sequence of if statements at worst. Stepping through the generated code instruction by instruction makes one very aware of this waste. Consequently, I wanted to do what our forefather assembler programmers could do: JMP or BR to an arbitrary address. Unfortunately, these capabilities were banned from Standard C to protect the masses.
However, gcc supports labels as values. Thus, instead of maintaining an integer state, I can store a starting address to the segment I want to execute next (hint this is reprint's program counter). Instead of wading through if statements and jump table lookups, this is just a single instruction branch. The code size and execution time savings easily become apparent on an MSP430, which is the first embedded processor to run reprint.
References:
https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
Great write up by Eli Bendersky
http://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
If you want to save code space in an embedded, you wouldn't use a huge monolith print function in the first place. Not every piece of software would require the entire collection of formats and parsing is kind of a luxury if you worry about the code space for switch statements. All those fancy new features isn't helping with bloat.
I code a minimal set of simple individual libraries functions for formatting my data and my I/O drivers, so no switch statements needed and the complier linker would keep track of what's needed in my bare metal embedded code.
Are you sure? yes | no
I agree with you 100%, but if you have the code space (and a little extra cycles) to spare then it's not an issue. For example, MSP430G2553 has 16KB of code space; reprint occupies a little under 3K; printf takes way more.
When you are writing an embedded web server with lots of different outputs, you sometimes save code space if all you need is a format string vs a series of function calls.
Are you sure? yes | no
Ah hah! Always wondered how efficient switch() statements were... Been using them quite a bit lately. Gonna throw this in the ol' bag of tricks!
Are you sure? yes | no