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

Help me: how to determine constant value at link time?

In ASM51, the following code is every useful:


-------- file1.asm ---------
public MAX
MAX EQU 10

-------- file2.asm ---------
extrn number(MAX)
MOV	A,#MAX

The point is that the constant value of MAX in file2.asm can be determined at link time.

I want the same effect in C51, that's to say, to define a constant as "extern". I have tried a lot of ways. One of them is:

-------- file2.C -----------
extern code MAX;
#define MAX_NUMBER ((unsigned char)&MAX)

C51 is trying to treat MAX_NUMBER as a constant, but the compiled result is much longer than the original one. Is there any better way???

Parents
  • I think your explaination is quite good and everything is OK. Unfortunately, you did not resolve the problem that: ONE MORE REGISTER IS USED AND MAKE THE FUNCTION UN-REENTRANTABLE, because in my project, the function is quite complexed and one more abuse of register will make the function un-reentrantable. If you replace MAX with a constant value such as

    #define MAX 5

    then the extra register will not be used and make the function reentrantable.

    Please note that my problem is to pass MAX as a constant whose value is defined in an ASM configuration file. In your example of passing it as a funtion parameter, it's meaningless to me.

    By they way, a function is inherently reentrantable if it only uses registers as local automatic variables. The "reentrant" keywork is using a software stack to realize reentrant feature. If you are not clear about this, you will hardly understant my question. For example, such functions as "memcpy", "isdigit" are reentrant (please refer to the manual), but they don't use software stack at all.

    Now. Please see the result of my "optimization defect" example:

    Example 1:

    #define MAX 5
    uint8 Test(uint8 i)
    {
    	if(i == (uint8)MAX)
    		return (uint8)MAX;
    	return 0;
    }
    The ASM code is:
    0000 BF0503            CJNE    R7,#05H,?C0140
    0003 7F05              MOV     R7,#05H
    0005 22                RET
    0006         ?C0140:
    0006 7F00              MOV     R7,#00H
    0008 22                RET     
    It has 3 instrunctions excluding "RET"

    Example 2:
    Just replace the define statement to:
    extern uint8 MAX[1];
    now the ASM code is:
    0000 AE07              MOV     R6,AR7
    0002 7F00        E     MOV     R7,#LOW MAX
    0004 EF                MOV     A,R7
    0005 B50601            CJNE    A,AR6,?C0140
    0008 22                RET
    0009         ?C0140:
    0009 7F00              MOV     R7,#00H
    000B 22                RET     
    It has 5 instrunctions excluding "RET"

    We exclude "RET" from calculation since in our real project, the function is quiet complex and the size grows larger, while the "RET" statment remains the same number of occurrence.

    Example 1, good result, nothing to blame.
    In example 2, Keil treat MAX as a variable and try to save it in a cache, which is R7, for further operation, this is what the "register variables" does.

    As a result, in the real project, if we use "extern uint8 MAX[1]" method to pass configuration constant, the function will become larger, exhaust all registers and make the function non-reentrantable.

Reply
  • I think your explaination is quite good and everything is OK. Unfortunately, you did not resolve the problem that: ONE MORE REGISTER IS USED AND MAKE THE FUNCTION UN-REENTRANTABLE, because in my project, the function is quite complexed and one more abuse of register will make the function un-reentrantable. If you replace MAX with a constant value such as

    #define MAX 5

    then the extra register will not be used and make the function reentrantable.

    Please note that my problem is to pass MAX as a constant whose value is defined in an ASM configuration file. In your example of passing it as a funtion parameter, it's meaningless to me.

    By they way, a function is inherently reentrantable if it only uses registers as local automatic variables. The "reentrant" keywork is using a software stack to realize reentrant feature. If you are not clear about this, you will hardly understant my question. For example, such functions as "memcpy", "isdigit" are reentrant (please refer to the manual), but they don't use software stack at all.

    Now. Please see the result of my "optimization defect" example:

    Example 1:

    #define MAX 5
    uint8 Test(uint8 i)
    {
    	if(i == (uint8)MAX)
    		return (uint8)MAX;
    	return 0;
    }
    The ASM code is:
    0000 BF0503            CJNE    R7,#05H,?C0140
    0003 7F05              MOV     R7,#05H
    0005 22                RET
    0006         ?C0140:
    0006 7F00              MOV     R7,#00H
    0008 22                RET     
    It has 3 instrunctions excluding "RET"

    Example 2:
    Just replace the define statement to:
    extern uint8 MAX[1];
    now the ASM code is:
    0000 AE07              MOV     R6,AR7
    0002 7F00        E     MOV     R7,#LOW MAX
    0004 EF                MOV     A,R7
    0005 B50601            CJNE    A,AR6,?C0140
    0008 22                RET
    0009         ?C0140:
    0009 7F00              MOV     R7,#00H
    000B 22                RET     
    It has 5 instrunctions excluding "RET"

    We exclude "RET" from calculation since in our real project, the function is quiet complex and the size grows larger, while the "RET" statment remains the same number of occurrence.

    Example 1, good result, nothing to blame.
    In example 2, Keil treat MAX as a variable and try to save it in a cache, which is R7, for further operation, this is what the "register variables" does.

    As a result, in the real project, if we use "extern uint8 MAX[1]" method to pass configuration constant, the function will become larger, exhaust all registers and make the function non-reentrantable.

Children
No data