How can I access variables from within the ASM block?

General discussion on mikroC.
Post Reply
Author
Message
pizon
mikroElektronika team
Posts: 823
Joined: 11 Oct 2004 08:53

How can I access variables from within the ASM block?

#1 Post by pizon » 12 Jul 2005 09:23

Q: (mikroC 2.1 and older) How can I properly access variables that are being declared in mikroC, from within the ASM block?

A: As you know, mikroC allows the user to mix assembly with C code. This is being done by using the asm statement (or block) within any function. This makes critical pieces of code (hotspots) as fast and controllable as they can be. However, the instructions within the asm block are not processed by the compiler in any way. This leads to 2 potential problems:
  • P1. If you intend to use a variable that was previously declared through C and you don't use it outside the asm{}, the compiler won't mark this variable as being used and will purge it from code, making it non-existent (and therefore unrecognizable) for the Linker;

    P2. The linker does NOT set the memory bank for the variables within the asm block. So, if the variable being used within the asm block is in another RAM bank than the one that was set before entering the asm block, your code will 'miss' the RAM bank, and consequently the variable itself.
There are several ways to cope with these issues:
  • S1. The easiest way to cope with this is to put a dummy variable assignment just before the asm code, like this:

    Code: Select all

    ...
      tictac = tictac;       // this line will be removed by the compiler,
                             // but the linker will get information that the
                             // global variable tictac has been used and
                             // will allocate memory for it
      asm {
        MOVF     _tictac,W
      }
    ...
    S2. Issue No.2 can be approached in several possible ways:
    S2a) Perform variable init just before the asm block:

    Code: Select all

    ...
          tictac = 0;
          asm ADDWF  _tictac,W ;
        ...
    This will set the correct bank (if necessary) for the variable being used in the asm{}. The drawback of this is that you cannot do this if your variable is to remain unchanged. In this case, you must

    S2b) Force the variable dummy init:

    Code: Select all

    ...
        unsigned short tictac;
        ...
          tictac = (unsigned short)tictac;
    
          asm ADDWF  _tictac,W ;
        ...
    This allways works, but produces some extra code (for the dummy init) before the asm block; nevertheless, this is the method is most often used at mikroE, since all the changes that occur during the code change are being handled by the compiler and linker.
    If you want to have things 'under a strong hand', you will like the following solution:

    S2c) Setting up the bank manually. This lets you 'sleep like a baby', but might generate too much extra code (for banking) if you have to access many variables from within the asm block:

    Code: Select all

    unsigned short tictac;     // suppose tictac is in bank1
            ...
          asm {
            BCF     STATUS,RP1
            BSF     STATUS,RP0
            MOVF    _tictac, W
            ...
          }
        ...
    This solution also requires some extra work, since you have first to do the compile, then take a look where (in which bank) has your variable been placed by the linker, and set the bank accordingly. And, if you change your code (add /remove some variables) the linker might re-position your variable and you'll have to do the banking 'detective work' again. In this case you could declare your variable(s) of choice with the absolute directive (and put them all in the same bank, for instance), and spare yourself the troubles after each code change;

Post Reply

Return to “mikroC General”