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

Mixed Memory Models

C51 v6.03+; uVision v2.07+

I want to build a Project with some files using the SMALL model, but most using LARGE.

If I select LARGE in the Target options, and specify SMALL in the C51 'Misc Controls' where required, or use a #pragma in the file itself, I get a fatal Compiler error:

RESPECIFIED OR CONFLICTING CONTROL

If I select SMALL in the Target options, and specify LARGE in the C51 'Misc Controls' box where required, everything Compiles OK, but I get Linker warnings for each of the 'Large' Modules:
L14: INCOMPATIBLE MEMORY MODEL

If I specify 'large' in each function declaration where required, it all Compiles and Links OK!

Thus it is possible to create a mixed-model Project, but extremely cumbersome to have to specify the model on every function!
Why doesn't it work when the model is specified at the module level?

(yes, I know you wouldn't want to design a Project like this from scratch, but this is "inherited" stuff...)

  • The problem is this:

    If you have a file (compiled in SMALL memory model) and another file (compiled in LARGE memory model) and both files call the printf library routine...which printf routine is included from the library? The LARGE model printf or the SMALL model printf?

    The answer is that this is an error condition.

    The memory model applies to the WHOLE program. It specifies not only the default variables space for YOUR functions but also the default variable space for the LIBRARY routines.

    When you create a program, you may specify the memory model on a function-by-function basis. For example:

    int my_func (int a, int b, int c) large
    

    But, you should note that any library routines that my_func calls are the small model versions.

    Jon

  • So if I don't use any (Keil) Library functions, or if I'm careful to make sure they're all the same model, I should be OK?

    Is it possible to specify explicitly which Library the Linker should use?

    If I had:

    #pragma LARGE
    :
    int my_func (int a, int b, int c) small
    would that call 'large' model libraries?

  • Could you also explain what the differences between the models available are, or do they ONLY change the default memory type?
    For example, what causes the stack efficiency in the large model to be worse than small?( P88 , C51 Compiler)

  • That's talking about the reentrant stack; not the 8032 CPU stack.

    The "reentrant stack" is a simulated stack created by Keil to support reentrant functions, due to the limitations of the 8032 CPU stack.

    The reentrant stack is used for parameters and locals; the 8032 CPU stack is still used for the return address (p97)

    Keil simulates the small reentrant stack in idata, the compact reentrant stack in pdata and the large reentrant stack in xdata - see p96.
    The large/compact reentrant stacks are less efficient because they're in xdata/pdata.

  • > Keil simulates the small reentrant stack in idata,
    > the compact reentrant stack in pdata and the
    > large reentrant stack in xdata - see p96.
    > The large/compact reentrant stacks are less efficient
    > because they're in xdata/pdata.

    You conclude that reentrant stack in idata more preferrable ?
    So, could you explain me which sense to simulate reentrant stack in idata ?
    Instead of simulated reentrant stack in idata can be used efficient native hardware stack (via SP and PUSH/POP instructions).
    Which sense in simulation ?

  • //main.c
    #pragma small
    extern myfunc(unsigned char n) large;
    void main(void){
      myfunc(55);
    }
    

    //large.c
    #pragma small
    myfunc(unsigned char n) large;
    //
    //...
    //
    myfunc(unsinged char n) large
    {
    //do something
    }
    

    (not tested, just think)

    1. Modify the "large.c" or just delete it, then translate the "main.c", the "main.obj" is same as before.

    2. Modify the "main.c" or just delete it, then translate the "large.c", the "large.obj" is same as before.

    3. Remove the word "large" in "main.c" and translate again, the "main.obj" should be changed.

    4. Remove the word "large" in "large.c" and translate again, the "large.obj" should be changed.

    5. So any changing in other modules does not effect the current file Compiling result.

    6. And different memory model in function declaration can get the different object file.

    7. The module level memory model just act as a default value when the function declaration do not have the special memory model selecting.

    8. And the Linker knows the memory model of each object(module), so the warning is shown when the objects have the different memory model.

    9. It is very important that the modules have the function body and other modules calling the function should have the same memory model of the function.

    10. So the "myfunc" should have the same memory model in the two files.

  • So if I don't use any (Keil) Library functions, or if I'm careful to make sure they're all the same model, I should be OK?

    Yep, but I haven't tested this.

    Is it possible to specify explicitly which Library the Linker should use?

    If I had:

    #pragma LARGE
    :
    int my_func (int a, int b, int c) small
    would that call 'large' model libraries?


    Yep.

    Jon

  • Could you also explain what the differences between the models available are, or do they ONLY change the default memory type?

    The memory model only affects the DEFAULT place where variables, function arguments, and local vars are stored.

    For example, what causes the stack efficiency in the large model to be worse than small?( P88 , C51 Compiler)

    This reference is to the reentrant stack. It is more efficient in SMALL model because the reentrant stack is stored in IDATA rather than XDATA.

    Jon

  • This looks right, however, remember that the C51 compiler can pass arguments in registers! So, that may affect the outcome of such an example.

    Sometimes, bigger example are better!!! :-)

    Jon

  • If the compiler is passing parameters in registers, surely the model has no effect on the parameters; it just affects where the compiler would have put them if it had not been able to use registers?

    Locals would still be affected (and reentrant stack usage, if appropriate).