Inline Assembly Macros

It is useful at times to gang together a set of inline assembly instructions into a macro - this technique can be particularly useful for making calls to inline assembly functions.  Here is an example from Freescale Set 4:

#define MC_RIPPLE_ELIM(u_ab, u_dc_bus, inv_mod_idx) \
#asm(ram p <- u_ab.) \
#asm(alu d = p; ram p <- inv_mod_idx.) \
#asm(call mc_ripple_elim, no_flush.) \
#asm(alu a = p; ram p <- u_dc_bus.) \
#asm(alu p = a; ram p -> u_ab.)

Under ANSI/ISO C rules, within a function-like macro the '#' token acts as a stringification operator - it must be followed by a parameter and it turns that parameter into a string constant.  So the above is actually invalid C code from a C preprocessing perspective.  To simplify things, when ETEC compiles code it passes the source through the C preprocessor in ETPUC mode, which allows the special keywords #asm and #endasm to pass without issue.  Additionally, the ETEC compiler processes the #asm, #endasm and #asm() directives regardless of whether they are the first text on a source line or not.  Thus, the macro above could also be written as:

#define MC_RIPPLE_ELIM(u_ab, u_dc_bus, inv_mod_idx) \
#asm \
ram p <- u_ab. \
alu d = p; ram p <- inv_mod_idx. \
call mc_ripple_elim, no_flush. \
alu a = p; ram p <- u_dc_bus. \
alu p = a; ram p -> u_ab. \
#endasm

Although not necessary, to write such macros in an ANSI/ISO compatible way, an extra level of mis-direction is required:

#define hash_asm #asm
#define hash_endasm #endasm

#define MC_RIPPLE_ELIM(u_ab, u_dc_bus, inv_mod_idx) \
hash_asm \
ram p <- u_ab. \
alu d = p; ram p <- inv_mod_idx. \
call mc_ripple_elim, no_flush. \
alu a = p; ram p <- u_dc_bus. \
alu p = a; ram p -> u_ab. \
hash_endasm