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.

extern variables defined in linked command file

Other Parts Discussed in Thread: MSP430F2274

Hi,

If I first see a definition in header file as


extern volatile unsigned char P2SEL;                              /* Port 2 Selection */

for which the true definition of unsigned char variable P2SEL remains undefined throughout all project files.
but in the end of liner.cmd file, we saw it links to another .cmd file by


-l msp430x22x4.cmd


and the linked .cmd file contains “P2SEL” in the following form:
/************************************************************
* DIGITAL I/O Port1/2 Pull up / Pull down Resistors
************************************************************/

P2OUT              = 0x0029;
P2DIR              = 0x002A;
P2IFG              = 0x002B;
P2IES              = 0x002C;
P2IE               = 0x002D;
P2SEL              = 0x002E;
P2REN              = 0x002F;

 

along with others. In this situation how does the compiler actually treat P2SEL in the .cmd file? And would it be regarded as a constant definition, an ordinary variable of type unsigned char, or an address or pointer?

  

Matt

  • Matt Shira said:
    how does the compiler actually treat P2SEL in the .cmd file?

    The linker creates a symbol named P2SEL and assigns it the value 0x002E.  Unlike other variables, no memory is reserved for it.  Since the location (a memory mapped register, I think) is supplied by the hardware, reserving memory is not necessary.

    Matt Shira said:
    And would it be regarded as a constant definition, an ordinary variable of type unsigned char, or an address or pointer?

    The rest of the compiler tools regard P2SEL as a variable of type unsigned char.

    Thanks and regards,

    -George

  • Georgem said:

    Unlike other variables, no memory is reserved for it.

    The rest of the compiler tools regard P2SEL as a variable of type unsigned char.

    Later in the code I see a line like:

    P2SEL &=  ~0x04;

    used for I/O port configuration, and was somewhat confused. Ordinarily the syntax would for changing a memory-mapped register value would be like

    *(type*)(address) &= ~0x??

    but in the P2SEL case above the "symbol" itself seems to behave like a pointer. Could you elaborate more on this?

  • No, the symbol P2SEL does not behave as a pointer, it behaves as what is technically called an "lvalue", i.e. an addressable data object.

    I use the C6000 family instead fo what you're using, but the principle is the same:  The compiler has built-in knowledge about certain machine registers, and in effect "predefines" them to have the right properies.  On the C6x, for example, the command/status register is accessible using the symbol "CSR", which acts as though it has been predeclared as: extern cregister unsigned volatile CSR;  The linker doesn't need to see a matching external symbol definition, because the compiler translates any access using that symbol to a "move to/from control register" instruction with the target register hard=coded into the instruction.  In some other cases, "peripheral" device registers might be declared in chip-support library headers along the lines #define P2SEL (*(unsigned *)0x123456) (or whatever), where again when an access is made using that symbol, the compiler coverts it to a "move to/from indirect" with the hard-coded constant (0x123456) for the indirect address, so again the linker doesn't know about the symbol.

  • Doug,

    In a C6000 compiler manual I found a example of CSR like this:

    extern cregister volatile unsigned int CSR;

    which is as what you examplified. CSR shoud be a special token which the compiler has knowledge about (similar to a keyword) and would act accordingly when converting C code into assembly.

    However the MSP430 case differs slightly in the case of

    P2SEL              = 0x002E;

    in two aspects:

    1) It is in linker .cmd so it is handled by linker rather than compiler. This is exactly what you described.

    2) Following your explanation I tried to fnd information on whether either or both "P2SEL" or value 0x002E has special meaning to the compiler/linker. However, there seems be no such information in the compiler or linker manual (actually assembler manual which includes linker description).

     

    I am still not sure what does this mean.

     

    To the moderator:

    Could you help to move this thread to MSP430 forum since the topic seems to involve some msp430 knowledge?

     

     

     

  • The external (linkable) symbol P2SEL is given the value 0x002E by the linker command file, which logically is an address and not the object itself (which in this case isn't allocated any storage by the linker).  The linker deals mainly with addresses, so when there is a reference from your C code to an external object using the name "P2SEL", the linker produces object code that refers to an object at the address 0x002E.  The linker does not see C or assembly-language code, nor final executable instructions and data; what it sees is a collection of partially completed executable code and data, along with special "relocation information" which the linker uses to complete the code by inserting the final run-time addresses of code and data objects.  (On some platforms, part of this linkage is done later, when the program is loaded into memory ready for execution.)  Names obtained from relocation information or otherwise handled by the linker always refer to addresses, even though the source code did not explicitly use a pointer value.

    This can at times be puzzling.  I recently had to use the following code to access the linker-defined symbol _STACK_SIZE in a C6000 program that I wrote to probe the environment: "extern unsigned far _STACK_SIZE;" and "printf("Stack size is %u bytes.\n", (unsigned)&_STACK_SIZE);", which seems peculiar but is consistent with what was going on with P2SEL in your case.  If you think about it and understand how the linker's "__STACK_SIZE=4096" results in this code printing "Stack size is 4096 bytes." then you will probably have attained the desired state of enlightenment.  (Don't worry about the extra leading underscore; it's really the same symbol, just spelled differently between C source code and the external object code.  Some implementations do that and some don't.)

  • George’s initial answer as well as Douglas’s following-ups are correct.

    P2SEL is defined in library header located in CCS installation folder “C:\ti\ccsv5\ccs_base\msp430\include\msp430f2274.h”

    msp430f2274.h

    #define SFR_8BIT(address)   extern volatile unsigned char address

    SFR_8BIT(P2SEL);                              /* Port 2 Selection */

     

    and later in linker they are assigned addresses which are the actual memory mapped registers’ addresses. Just as George said P2SEL and alike are all treated as unsigned chars. They are not anything like “pointer” which I initially incorrectly regarded as.

    I think it is not like “CSR” because CSR and other processor control registers are c6000 compiler’s intrinsic knowledge; however knowledge about “P2SEL”’s are in fact supplied by “msp430f2274.h” and the .cmd file. Douglas’s explanation:

    Doug

    In some other cases, "peripheral" device registers might be declared in chip-support library headers along the lines #define P2SEL (*(unsigned *)0x123456) (or whatever),

     

    was correct on this regard.

    Thank George and Doug for the fine explanations. This is a very basic question and we just took some time to get familiar with the conventions in the msp430 codes.