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

differences of absolute locations

I want an instance of a structure to be put at a specific address in xdata. What is the difference between these declarations:

#define tSetupPacket (* (tDEVICE_REQUEST xdata *)0xFF00)

tDEVICE_REQUEST xdata tSetupPacket _at_ 0xFF00;
It seems that the second behaves incorrectly.
There is also an opportunity to declare a structure at absolute locaiton by #pragma memory segments (supported by non-Keil C or Keil linker).
What is the best choice?

  • "It seems that the second behaves incorrectly."

    in what way?

  • All the fields of the setup packed defined by the second declaration are zeroes, while they are not.

    There is 1 more reason to love the first declaration style. These declarations can be used in H file. This means no extern import is required in C modules. Unfortunately I've faced a problem. I cannot declire an array using this style, i.e. the following does not compile:
    #define InEndpoints (* (tEDB[3] xdata *)0xFF48)
    where tEDB is a structure.
    Can you help me?

  • What is the difference between these declarations:

    #define tSetupPacket (* (tDEVICE_REQUEST xdata *)0xFF00)

    tDEVICE_REQUEST xdata tSetupPacket _at_ 0xFF00;


    Well, the first is not a declaration. It is a macro. There is no symbolic information generated for it and it cannot be referenced by name in a debugger. There is no memory space reserved for the object, so the link could actually place other objects at address 0xFF00.

    The second is an absolute declaration. The object is not initialized (and is filled with 0's according to ANSI specification). Space for the object is reserved and a symbolic name is generated. This variable can be viewed or watched by name in a debugger.

    Jon

  • Some more random opinions:

    The macro form is the most portable. As Jon points out, you'll need to be sure that nothing actually links there. Typically, I'd see this sort of thing for memory-mapped hardware, and the linker would be configured to reserve the upper memory range for a whole series of registers. The other use I'm accustomed to is memory area shared between separately linked programs (e.g., boot loader and application code).

    The second form is convenient, but depends on Keil-specific language extensions. Tools other than the compiler (such as lint or your syntax-coloring IDE) will have to be taught how to deal with the non-standard syntax in your source. Portability goes down.

    The third form (linker spec) requires the variable to live in its own segment, which for Keil essentially means its own file. Every linker will have a different way to control segment positioning, so this method is in practice not very portable -- though at least there's nothing in the source code that will cause compiler errors. I also tend to avoid this approach because it puts the (important!) information about the variable address in a relatively obscure place. You probably want to know when browsing the C source that this variable is special and represents an absolute address. This method is more tempting to me for a shared memory area than for defining hardware registers.

  • Thanks.
    All you agree that the second form is a valid one. Nevertheless, it is always zero, i.e. writing to the structure's fields does not modify it. So, something is still wrong.