This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

asm code included in C/ASM?

Other Parts Discussed in Thread: MSP430F5529, OMAP-L137

Hi,

I use CCSv4 and I need a common header file included in C and assembler modules. The part that I need is a kind of macro that contains (is translated to) assembler instructions.
for example:

File:  header.h

#define R45 \
   asm( " pop r4");\
   asm(" pop r5");

When I include it into C, e.g. file module.c:
#include "header.h"

and use R45 macro in the C funtion macro, the asm code is inserted properly.

Unfortunatelly, when I try to use the same header to be included in assembler module, lets's call it module_a.asm by:

.cdecls C,"header.h"

The R45 symbol cannot be exchanged to the macro contents (i.e. two instructions: pop r4 pop r5).

Is it possible to have such common part of the code for C and assembler?

Regards,
Piotr Romaniuk, Ph.D.
ELESOFTROM

 

  • Hi Piotr,

     

    When using the cdecls statement the compiler defines the macro __ASM_HEADER__ which can be used to create a C version and an assembler version.

    That gets rid of the "asm ( )" problem but I'm not sure if you can create a 2line macro using "define..." as easily in assembler so you might have to use a full assembler macro definition in which case you would end up with something like:


    #ifndef __ASM_HEADER__

    // macro for C files...
    #define R45 \
       asm( " pop r4");\
       asm(" pop r5");

    #else

    // macro for ASM files...
    R45     .macro
               POP    R4
               POP    R5
               .endm

    #endif

    I haven't got a compiler on this PC but I'm pretty sure it should work!

     

    Regards,

    Chris.

  • I am afraid it will not work. When you include C header by .cdecls it is processed by C compiler, it cannot understand:

    chris_m said:
    // macro for ASM files...
    R45     .macro
               POP    R4
               POP    R5
               .endm

    because it is in assembler syntax but not C.

    If you include it by .include #ifndef will be not working, because assembler source is not passed through preprocessor, so assembler syntax is expected.

    Reards,
    Piotr Romaniuk, Ph.D.
    ELESOFTROM

  • I thought about my version of asm( ) instruction that could be resolved to:

    1) asm(" ") or
    2) only the argument depending on the source type that it is included for.

    This is cosmetic trasfrormation of your proposition, but unfortunately, the problem is deeper.
    The header included by .cdecls cannot create multiline text.

    Please note that:

    #define SOME_MACRO first_part \
                                                second_part

    According to C preprocessor specification or the C syntax (i.e. backslash meaning) the definition is in fact:

    #define SOME_MACRO first_part  second_part

    chris_m said:
    I'm not sure if you can create a 2line macro using "define..."


    So I think that it is not possible to create multiline macro this way.

    Regards,
    Piotr Romaniuk, Ph.D.
    ELESOFTROM

     

  • Piotr Romaniuk said:
    .cdecls it is processed by C compiler,

    Yeah you're right the .macro wouldn't work. 

    #define definitely works for single lines e.g. "#define WIBBLE       BIS.W    #1, R12" but I haven't tried it for double lines - I assume you tired it but couldn't get it to work ?

  • chris_m said:
    I haven't tried it for double lines - I assume you tired it but couldn't get it to work ?

    If I only could express two lines by #define.
    Please note that:
    #define PSEUDO_TWO_LINE_MACRO    part_one \
            part_two

    is translated by preprocessor to one line (you can check it in .pp file that is generated from preprocessor).

    Regards,
    Piotr Romaniuk, Ph.D.
    ELESOFTROM

     

  • (I started writing my previous post before you submitted the first post about the preprocessor and multi line defines - I don't doubt your comments I just hadn't read them yet!! :-) ).

     

    In that case the only valid solutions I can think of are to split the macro into single lines or to use two separate header files - one for the C files and one for the asm file (using .include to allow the .macro statement).  If the C header has other important things to share with the asm file then the __ASM_HEADER__ can block the "asm(...)" statements from being compiled for the assembler file.

     

    I have never needed to use multi-line macros in the way you are wanting to (as I am sure you will have guessed from my posts to this thread!) but would be interested to know of any cunning solutions you may come across in case I do ever need to use them in the future.

     

    Regards,

    Chris.

  • A slightly better option than two completely separate files would be to create the two definitions (one for C and one for Assembly) in the same file and use a #if to select which one is active.  This still requires two separate definitions which is always scary but at least they will be close together and reduce the possibility of updating one without updating the other.

    Jim Noxon

     

  • Hi Jim,

    Jim Noxon said:
    A slightly better option than two completely separate files would be to create the two definitions (one for C and one for Assembly) in the same file and use a #if to select which one is active.

    (i) The best option is to have one code translated to assembler or C. The source is one and in one place and it is translated into proper form depending on a type of the targed module where it is included. (ii) Worse option is one file with two forms (something like you suggest). (iii) The worst option is solution with two separated files: one for assembler and one for C.

    Unfortunately, I can achieve my aim only by (iii) under Code Composer Studio v.4.
    Jim, can you write something more about solution that you suggested? Please read other posts in this thread, I am not sure but it was probably discussed. I hope I missed something.

    Regards,
    PIotr Romaniuk, Ph.D.
    ELESOFTROM  

     

  • Hi Piotr,

    I use IAR, not CCS, and option (ii) works in IAR.  The IAR assembler supports #if directives (and a few other C-style directives), so when the assembly language file #include's the header file, it processes the #if / #else / #endif directive correctly and goes the assembly-language portion.  With some effort, one could produce a solution that uses option (i). 

    By your observations, it would appear that the CCS assembler does not properly handle #if / #else / #endif directives.  If that is really true, then what do the processor-specific peripheral map files look like?  Is there a single include file that you can include from either C or assembly language?  In IAR, for example, one file like "MSP430F5529.h" declares the peripheral map for both assembly language and C.  Just one include file.  Does CCS do the same?  And if so, how can they do it without assembler support for #if / #else / #endif?

    Jeff

     

  • Piotr Romaniuk said:
    Jim, can you write something more about solution that you suggested? Please read other posts in this thread, I am not sure but it was probably discussed. I hope I missed something.

    My mistake.  No you didn't miss something.  However, all is not lost.  Just need to do things a bit backwards that's all.  Let me explain...

    First of all create the macro in an assembly include file like this

    now include it in all of your projects assembly files by declaring it in the project options properties dialog

    and declare it here (you may need to copy the picture and look at it in another viewer)

    Now all your assembled files will include this file with the macro.  Including all your C files because the code gen tools will create assembler files from your C source and then in the assembly step this file will get included.  Effectively including it in all of your C files.

    Now you can call the macr in your assembly file just like you normally would.  Here I created a simple main_x function to call

     Create a compatible C header file for the macro (and in this case the function too).

    Finally, call the macro and function in your C file like this

    This compiles and links without error and when run in the debugger you can see all is working as expected

    Granted, this code will crash if it is actually run but you can see all the necessary interworkings are appropriately applied and operating.

    Now you only have a single macro to manage.  The additional C header file could be omitted as the function prototype could be from a different file and the C macro definition isn't really necessary.  Either way, if you choose to keep the additional C header file it only manages access to the macro and thus still keeps only one definition in the project.

    Hope this works for you,

    Jim Noxon

     

  • Hi Jim,

    Thank you for detailed explanation. 'Simulate source .include' is very interesting feature, I did not know it.
    It solved my problem, thank you again.

    Regards,
    Piotr Romaniuk, Ph.D.
    ELESOFTROM

  • Hi Jeff,

    IAR file processing looks litle different,

    Jeff Tenney said:
    By your observations, it would appear that the CCS assembler does not properly handle #if / #else / #endif directives.

    It is a case of incorrect behaviour of CCS, but rather limited functionalities and specific processing.
    There are two options for including source into assembler:
    1) by .include , so included source is in assembler syntax,
    2) by .cdecls , when included file is in C and is preprocessed.

    In (2) preprocesor functionality is very limited.

    Fortunately, there is another feature in CCS that solves the problem.

    Regards,
    Piotr Romaniuk, Ph.D.
    ELESOFTROM

     

  • Hey,

     

    I'm working on an OMAP-L137 and I found this feature really interesting.

    There is only one thing I can't get, it's how to use C variables in these macro. First, is it possible ?

    Because I tried many ways, but none worked.

    I also tried other ways like defining asmfunction with .asmfunc so that I could call the function as a C function but it messes with the registers (saving and restoring, that I don't want and I can't find any way to make this asmfunction 'naked').

    Or the latest I tried was with asm statement but I didn't find how to pass C variables as parameters in these statements.

     

    Is there any easy way to do what I want to do ? I hope I was clear enough in the definition of my problem.

     

    Regards

  • In this case, there are some limitations to accessing C variables from the assembler.  The easiest method is to declare the variables you want access to as global variables.  This way you know they are located at a specific address and can access them by simply using the cdecls directive to share them between C and assembly.  Of course, if you need to use re-entrant code this option isn't available to you.  In this case, you need to access the locally defined variables and/or those passed as parameters.

    If you want access to the passed parameters, you have to pay attention to the calling convention for the processor you are working with.  Since the OMAP-L137 has two processors, you need to reference the appropriate manual.  For the C6xxx processor, this would be http://www.ti.com/lit/ug/spru187q/spru187q.pdf.  For the ARM processor, it would be http://www.ti.com/lit/ug/spnu151g/spnu151g.pdf.  The applicable sections in both compiler guides are the sections describing the calling convention within the run-time environment chapter.

    Unfortunately, there are some limitation regardless of the processor you will be working with.  Namely, the registers where parameters are placed is only guaranteed to be correct at the point of entry to the function.  Once past this point, the optimizer is free to modify those registers as needed.  The real purpose for describing the calling convention is for you to write specific assembly routines as you are now in full control of the operation once the function is entered.  Thus, within a C/C++ function, there is no guarantee the first parameter passed will still be in register R0 (for the ARM) at any point within the function because you don't know the optimizer hasn't already moved that value to someplace else before the first line of source in the function.  The only possibility you have of placing parameters in known places is to use the ellipsis (...) operator in the declaration of the function and only declare the first argument.  This will force all variables to be place physically on the stack and you can then access them that way.  The down side of this is you lose most of the type checking capability of the compiler with functions like these.

    As for accessing local variables themselves, the compiler guides do not dictate any layout schema for either the stack frame or the register sets.  Only that some space will be allocated if needed.  In this case, there really is no solution beyond implementing your own assembly function.

    As far as creating naked asm functions, the only real way to guarantee this is to write it in assembly.  Another, unofficial way, is to write the entire function using only asm statements with the optimizer set fairly high.  If there are no C/C++ recognizable source statements (other than the asm statements), many times the compiler/optimizer will generate the naked function.  Unfortunately, this is not guaranteed by the documentation and could change on any upgrade of the code gen tools.  Generally, if you go this route, I would suggest you turn on the option to keep this generated assembly file, and once you generate it and have taken a look at it to make sure it is what you want, exclude the C source file and include the generated asm file for normal builds.

    Bottom line, if you want to access variables from C in assembly, you pretty much need to write assembly functions and pass the variables using normal C function calls.  These functions can be relatively small and still be pretty efficient.

     Jim Noxon

  • Thanks a lot Jim, I'll be working on it.

     

    Regards

     

    Maxime

**Attention** This is a public forum