This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to fine tune a piece of C code into macro?

I have a piece of C code,


if(u3Varaible0 > u3Variable2)
{
#ifdef DEF_SOMETHING
.
.
#else
.
.
#endif
}
else
{
.
.
.
}


The variable length of u3Varaible0 is 3 bytes. I don't want to declare it as "unsigned long"(inorder to save onchip memory and reduce execution cycles), So I have to write this piece C code into asm code look like


CLR C
MOV Au3Varaible0_L
SUBB A,u3Variable2_L
MOV Au3Varaible0_M
SUBB A,u3Variable2_M
MOV Au3Varaible0_H
SUBB A,u3Variable2_H
JC C0049
.
.
.
.
C0049:
.
.
.


I want it be a macro(inorder to reduce execution cycles).
But now comes the problem:
1.
If I write this code as a asm macro in an asm source. I just can't use this macro from a C code.

2.
If I try to write is as C macro using #define, It is impossible to use inline assembly in the macro!!

3.
#ifdef DEF_SOMETHING
will also cause an error in #define macro


Does anyone know another good way to solve this fine tune problem?

  • It should be possible to expand a macro that includes in-line assembly, I have never done it myself.

    If you are really so very desparate for code and memory space, you will have to write your entire functions in assembler. This might be worth the effort if you are writing an ISR or perhaps you have to handle many 24-bit values in a very short time.

    But, before you do that, consider that there are many compiler optimisations that cannot be performed on code with in-line assembler. Consequently, you may loose more than you gain.

  • "I want it be a macro (inorder to reduce execution cycles)."

    Eh?

    How does making it a macro reduce execution cycles?!

  • "The variable length of u3Varaible0 is 3 bytes. I don't want to declare it as "unsigned long" (inorder to save onchip memory and reduce execution cycles)"

    Are you sure that making it 'unsigned long' will actually hurt that much?



    If you want to write in 'C', then you will have to use the data types that 'C' provides.

    'C' is designed to work with these data types - you will probably find that it actually does it quite efficiently.
    If you are an accomplished assembler programmer, you may well be able to beat the compiler - but then, if you are an accomplished assembler programmer, you should have no problems implementing a set of 24-bit arithmetic functions...

  • typedef struct
        {
        bytes[3];
        } U24;
    

    You can write arithmetic routines to manipulate (assign, add, subtract) these U24s either in C or assembler. Or, if you're willing to perhaps lose a few instructions, do the math in U32s and cast the result back. In the second case, you might want some other sort of access, like:

    typedef struct
        {
        U8  msb;
        U16 lsw;
        } U24;
    

    Or a union of the two.

    Generic pointers happen to be three bytes, so you might get away with using U8* or void* as the type. This is perhaps a little unclear, as you're not really pointing to anything. On the bright side, you can use the built-in compiler operations to do math on the pointers.

  • "On the bright side, you can use the built-in compiler operations to do math on the pointers."

    Hmm... not so sure about that bit: Although the Generic Pointers occupy 3 bytes, they are not 24-bit numbers.
    I somehow doubt that adding 1 to a Generic Pointer containing 0x00FFFF will give you 0x010000 - which is what you'd want for 24-bit maths

  • I somehow doubt that adding 1 to a Generic Pointer containing 0x00FFFF will give you 0x010000

    I'm pretty sure it won't work in the general case. Far pointers to xdata will probably work, but the ranges where that high byte represents other memory spaces will be problematic.

    And there have been other threads about the fun and excitement of trying to compare a pointer to NULL, when the 8051 has three or four different NULL pointer values.

    One of the problems with implementing routines for this data type (even in assembler to be called from C) is that there is no way to pass two three-byte struct values in registers, nor return one, given the C51 calling conventions. Whatever you gain in efficiency in the routine is going to be lost in the parameter passing.

    Conversion to a U32 involves grabbing a byte not part of the structure and shifting or masking. But it's probably a cleaner way to go even at that, and certainly safer.

    (Should I add 24-bit arithmetic to my wish list, right after the wish for 64-bit arithmetic?)

  • "But, before you do that, consider that there are many compiler optimisations that cannot be performed on code with in-line assembler. Consequently, you may loose more than you gain."

    [Ovid]
    That's why I prefer to write my project in C code with only some asm code(need to be fine tune).

  • [Ovid]
    If this subroutine is a macro, I can save function call and return instructions(puch PC to stack and pop them back )

  • [Ovid]
    Yes, I'm sure.
    If I declare it as unsigned long.

    ; unsigned long a,b;
    ; if(a>b)
    ; SOURCE LINE # 77
    MOV R7,b?042+03H
    MOV R6,b?042+02H
    MOV R5,b?042+01H
    MOV R4,b?042
    MOV R3,a?041+03H
    MOV R2,a?041+02H
    MOV R1,a?041+01H
    MOV R0,a?041
    SETB C
    LCALL ?C?ULCMP
    JC ?C0001

  • Hi thanks to all.
    Execuse me. My main purpose is not to solve
    3 bytes length variable problem. It is just an example.
    I'm trying to focus on how to sove the following three problems.

    1.
    If I write this code as a asm macro in an asm source. I just can't use this macro from a C code.

    2.
    If I try to write is as C macro using #define, It is impossible to use inline assembly in the macro!!

    3.
    #ifdef DEF_SOMETHING
    will also cause an error in #define macro

  • 1. This seems reasonable, if inconvenient, since the assembler syntax is not understood by the compiler, any more than the assembler understands C function call syntax.

    2, 3. ANSI C prohibits a preprocessor macro (#define) from generating further preprocessor directives. So a #define can indeed not expand into a "#pragma asm" or "#if defined()". (This restriction is one of the more awkward points about trying to play nice and use the standard #pragma syntax, instead of adding extension keywords or the GNU-ish __attribute(foobar).)

    The easiest way, IMO, to link C code with assembler code is to write subroutines in assembly that conform to the C calling conventions. Then add extern definitions to a header file, #include that header, and call the function as normal.

  • "1. If I write this code as a asm macro in an asm source. I just can't use this macro from a C code."

    Here is your fundamental problem: 'C' and assembler are different languages; they have different semantics and different syntax rules. It should therefore come as no surprise whatsoever that assembler source does not work in 'C', and vice-versa

    Write 'C' source code in your 'C' source files, and assembler source code in your assembler files.

    If something needs to be written in assembler, then write it in assembler in an assembler source file.

  • So,the conclusion of this topic:
    If we have a routine in assembly code and want to use it at many playces from C code. Function call is always necessary, macro is impossible. There is no way to save "push and pop program counter" instructions.

  • "If we have a routine in assembly code and want to use it at many playces from C code. Function call is always necessary, macro is impossible."

    Correct.

    "There is no way to save 'push and pop program counter' instructions."

    If this is a real problem to you, then you should be writing in assembler anyway.

    Just extend your assembler function so that it encompasses all the bits that need to use this macro - and call this larger function from 'C'.
    Thus you can use your assembler macro in its proper environment (an assembler source file), and only have one call/return overhead from 'C'.

  • If this is a real problem to you, then you should be writing in assembler anyway.

    I do not know what is happening, but recently there has been a swarm of posts "why can C not do what assembler can".

    Hey Guys, if you want the pleasure of C, do not complain about the pain.

    It is emminently possible and practical to mix C and assembler files but do not attempt to mix C and assembler statements

    Erik