CBA Podcast

episode 34: Rust, coroutines and cohosting


Listen Later

Finally, the "we" in announcements doesn't just mean the royal we / majestic plural, but there's an actual co-host! Introduction is in the audio contents, so I guess you'll just have to listen.

We talk about first contact with the Rust programming language, coroutines for implementing lightweight tasks/threads, various smaller topics and some upcoming events.

Links:

  • Rust programming language:
    • Discover the world of microcontrollers through Rust!
    • The Embedded Rust Book
    • LLVM Intermediate representation
  • Coroutines / protothreads:
    • Coroutines and simpler protothreads for building stackless cooperative tasks
    • Protothreads under the hood: Duff's device or GCC's computed goto
    • convoluted example: 6502 asm + Tcl = protothreads
  • short video of VGA generator board in action
  • RetroChallenge 2019/03 (whole month of March) is open
  • Maker Faire Ruhr (DASA, Dortmund, DE): 23+24 March
  • HCC!retro meeting (Bilthoven, NL): 16 March

Here's a code snippet hopefully illustrating what I called "coroutines" and should probably have been called "protothreads".

Function "print_2nd_word" is a protothread. It can be called repeatedly passing a character each time. Only the 2nd word is printed, one character at a time.

void print_2nd_word( char c ) { CR_BEGIN; while ( c != ' ' ) CR_YIELD; CR_YIELD; // skip space while ( c != ' ' ) { putchar( c ); CR_YIELD; } }

To do this, the function keeps track of where it exited last time it was called, using a number of macros:

#define CR_BEGIN static void *jmp = &&lbl_crstart; goto *jmp; lbl_crstart: ( void )jmp; #define CR_YIELD do { jmp = &&GLUE( lbl, __LINE__ ); return; GLUE( lbl, __LINE__ ): ( void )jmp; } while ( 0 )

"CR_BEGIN" is basically setup-code.

"CR_YIELD" is the simplest primitive in this context, and does: exit the protothread function, and resume at this point next time it's called.

More advanced macros - e.g. to repeatedly wait for an event - can be built on top of, or in the same way as "CR_YIELD".

Note that these macros use GCC's "computed gotos" (i.e. take the address of a C label, and jump to that address using "goto"). Here's an implementation of both macros using ANSI C:

#define CR_BEGIN static int cr_st = 0; switch( cr_st ) { case 0: ; #define CR_YIELD do { cr_st = __LINE__; return; case __LINE__: ; } while( 0 ) #define CR_END CR_YIELD; }

(In this case, an additional macro "CR_END" is necessary as glue to conform to C syntax/nesting.)

Funfact: it's a bit of a PITA to add sourcecode to this page.

...more
View all episodesView all episodes
Download on the App Store

CBA PodcastBy Michai Ramakers