• Join
  • Sign In with my.TI Login
Texas Instruments
  • Products
  • Applications
  • Tools & Software
  • Support & Community
  • Sample & Buy
  • About TI
Sample & Purchase Cart Sample & Purchase Cart
  • Search
  • Advanced
TI E2E™ Community
  • Support Forums
  • Blogs
  • Groups
  • Videos
  • 简体中文
  • More ...
TI Home » TI E2E Community » Support Forums » Microcontrollers » MSP430™ Microcontrollers » MSP430 Ultra-Low Power 16-bit Microcontroller Forum » crash with indexed CALLA instruction from flash
Share
MSP430™ Microcontrollers
  • Forum
  • Announcements
  • E2E Wiki
Options
  • Subscribe via RSS
MSP430 Resources
  • MSP430 Product Folder
  • MSP-EXP430G2 - MSP430 LaunchPad Value Line Development kit
  • MSP430 Getting Started Guide
  • MSP430 Microcontroller Projects
  • More Resources >
  • crash with indexed CALLA instruction from flash

    crash with indexed CALLA instruction from flash

    This question is answered
    Jens Potschadtke
    Posted by Jens Potschadtke
    on Apr 05 2012 09:03 AM
    Prodigy110 points

    Hello,

    today I just discovered a strange behaviour of my code when I transfered a jump table from RAM to Flash on the CC430F6137 controller.

    When the code wants to jump to an entry of the table with a CALLA instruction, it crashes (sets PC to 0x0F3FFE)

    If the table sits in RAM then everything works as expected. When the same table is placed in FLASH, the app crashes.

    This is the code with the table placed in ROM (at address 0xc272):

    0x08226:   4F6F                MOV.B   @R15,R15

    0x08228:   118F                SXT     R15

    0x0822A:   065F                RLAM.W  #2,R15

    0x0822C:>  135F C272           CALLA   0xc272(R15)

    At the time of the CALLA instruction, the R15 has the content 0x10. But even with 0 the app crashes.

    Coil_module = 0xc272

    B372     0000     B3A4     0000     B378     0000     B37E     0000     B352     0000     B242     0000     B390     0000     B3A8     0000

    The intended jump address is 0xB352, which I verified to hold the wanted function.

    First I thought it is the alignment, which in this case is aligned only to 2 bytes, not to 4 bytes. But even with an alignment of 4 Bytes for the table the app is crashing.

    -----------------------

    Now, when I place the same table in RAM (here also with alignment 2), the code is working:

    0x08228:   118F                SXT     R15

    0x0822A:   065F                RLAM.W  #2,R15

    0x0822C:   135F 28DE           CALLA   0x28de(R15)

    Now, for security reasons and for restricted RAM space, I just want to place the jump table in ROM. Is there any way to make the call work?

    Is this a hardware bug? Is this documented somewhere?

    Well, the errata CPU33 of the document SLAZ052J, looks similar, but is states that this is only applicable when

    Quote:

     This erratum applies only when the instruction sequence is: PUSH or
    PUSHX followed by CALLA index(SP).
    This erratum does not apply if the PUSH or PUSHX instruction is used in
    the Register or Immediate addressing mode.
    This erratum applies only when SP is used as the destination register in
    the CALLA index(Rdst) instruction.

    I use the CCS  Version: 4.1.3.00038  and use the CCS compiler.n The original code is in C.

    Greetings and happy easter,

    Jens

    CC430 MSP430 microcontroller CCSv4 eZ430-Chronos CCS 4 msp 430
    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    All Replies
    • Jeff Tenney
      Posted by Jeff Tenney
      on Apr 05 2012 12:02 PM
      Guru10795 points

      Hi Jens,

      Really good post, I say.  Seems pretty clear you have a silicon bug on your hands.  I've never seen that one documented before.

      Hey TI, somebody needs to look at this one.

      I guess I'm not too surprised that nobody has ever found it before.  It is an odd thing to have a const array of function pointers.

      The workaround should be simple even if you leave the table in flash.  Please post again if you can't seem to work around it.

      Jeff

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 05 2012 12:15 PM
      Verified Answer
      Verified by Jens Potschadtke
      Guru140135 points

      Jens Potschadtke
      it crashes (sets PC to 0x0F3FFE)

      This looks like reading from vacant memory location 0x3fff, 0x3fff

      Alignment is not a problem, for reading 16 or 20 bit access, only word alignment is required.

      Jens Potschadtke
      errata CPU33 of the document SLAZ052J, looks similar,

      This erratum is due to the fact that both, push and call, are writing to the stack and modifying the SP. IF SP is then also used as index for the CALLA target, things go wrong. In your case, the index register is R15, so no problems apply.

      Actually I don't know what's wrong with your code. Initially, I though about a problem with 64k range, with the table being above 64k or such.

      However, why do you use CALLA? the 6137 doesn't have more than 64k, so using CALLA is a waste of space and clock cycles. A normal CALL will do.
      And why do you use SXT? The index is definitely always positive, so there must not be any sign to extend. And the MOV.B instruction will clear the high-byte implicitely.

      The MOV.B R15,@R15 looks a bit strange. Why do you pass the parameter by reference and not by value (if this is what happens here)? But it shouldn't have any influence. If you say that R15 contains 0x10 (hmm, the table you posted is only 0x10 bytes long, so the index is out of range. But maybe real table is longer than you posted) and the problem also appears with R15 == 0, the parameter isn't the problem.

      What if you use

      MOVA @R15,R15
      CALLA R15

      You can check R15 with a breakpoint on CALLA

      Ah, I guess I know what happened: From the 5x family users guide:

      "Indexed mode: Call a subroutine at the 20-bit address contained in the address pointed to by register (R5 + X); for example, a table with addresses starting at X. (R5 + X) points to the LSBs, (R5 + X + 2) points to the MSBs of the word address. X is within R5 + 32 K. Indirect, indirect (R5 + X)."

      In indirect mode, the register is the base address and the static value is the index. The two roles are usually exchangeable. But not in this case. It address is not fetched from 0xC272+R15, but from R15 + 0xC272, and 0xC272 is a signed value. Since you're using CALLA (20 bit addressing), the generated address is R15-0x03d8e which is (for R15==0) = 0xFC272. Which is vacant memory and returns 0xF3FFF as result.

      Sicne CALL is a 16 bit instruction, it wouldn't happen with CALL.

      It's easy to forget that the constant part of an indexed instruction is the index, not the register. And that the index is signed. And on 20 bit instructions, the signed rollover leaves the 64k range. (I must admit that it took quite some time for me to figure it out)

      Solution: either move the destination in to R15 as I suggested, by using word instead of address instructions, use CALL (which would shrink the jumptable as well as speed up and shrink your code) or calculate the index address in R15 first with word instructions and then use indirect mode CALLA @R15.

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jeff Tenney
      Posted by Jeff Tenney
      on Apr 05 2012 13:26 PM
      Guru10795 points

      Very nice catch, JMG. No silicon bug after all.

      I believe the OP Jens said his compiler generated this code, so I think you found a bug in CCS.

      What makes this so strange is that it's a 20-bit instruction with only a 16-bit index!  Only CALLA and MOVA are like that.  All other 20-bit instructions use a 20-bit index for indexed-mode addressing.  It's a little bit confusing.

      So would MOVA 0xC272(R15), xyz  still read from the wrong address like CALLA ?

      Jeff

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 10 2012 07:56 AM
      Guru140135 points

      Actually, CALLA, MOVA and RETA are the only instruciton dealing with 20 bit address range (except for plain register/register instructions) but not having the Prefix word that stores the upper 4 bits of 20 bit arguments.

      For MOVA, you can use MOVX.A and get a 20 bit argument. At the cost of an additional cycle and an additional instruction word. (well, better than having 32 bit operands)

      I guess, nobody thought that a CALLX.A instruction would be needed.

      However, the OP didn't say anything about compiler, and the code looks like hand-crafted assembly. I don't think the compiler will generate a jumptable like this. And the linker just links what is given to it for linking.

      There are several other ways to do it. Use MOVX.A (not MOVA) to load the target address into R15, then CALLA R15. Or call the jumptable itself directly. The table is preceded by an  ADD R15, PC,  and the jumptable contains branch instructions, not just addresses. And more.
      I agree, that the probelmatic way is the most obvious. But unfortunately a non-working one if the table is above 0x8000.

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jeff Tenney
      Posted by Jeff Tenney
      on Apr 10 2012 10:28 AM
      Guru10795 points

      Jens Potschadtke
      I use the CCS  Version: 4.1.3.00038  and use the CCS compiler. The original code is in C.

      I think this really is a CCS bug.

      I'm guessing the OP has a const array of function pointers.  I'm guessing when he removes the "const" his code works just fine.

      Also, because RETA is really just MOVA @SP+, PC, it really is just the two instructions CALLA and MOVA that are limited this way.  They are 20-bit instructions, but when using indexed addressing they use only a 16-bit index.  They are the oddballs.  As JMG pointed out, MOVX.A provides full functionality, but there is no CALLX.A, so one must restructure the code.

      Jeff

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 11 2012 09:29 AM
      Guru140135 points

      Jeff Tenney
      Jens Potschadtke
      I use the CCS  Version: 4.1.3.00038  and use the CCS compiler. The original code is in C.

      Well, my eyes aren't getting better by staring at other people's code :)
      I didn't see this even when I was specifically lookign for it.

      Well, the original code would be interesting.

      Jeff Tenney
      I think this really is a CCS bug.

      Yes, it if was C code then indeed this is a bug in large code model (small code model won't use CALLA, and for CALL it works)

      Jeff Tenney
      I'm guessing when he removes the "const" his code works just fine.

      Definitely, as the array then is copied to ram and I don't know any MSP with RAM above 0x8000 :)

      Jeff Tenney
      there is no CALLX.A, so one must restructure the code

      Yep. A possible restructuring is to separate the function call from the table by first fetching the destination into a variable and then doung the call using the already fetched variable. However, compile roptimization might undo this workaroun (sometiems, compilers can be too smart)

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens Potschadtke
      Posted by Jens Potschadtke
      on Apr 11 2012 11:04 AM
      Prodigy110 points

      Hello,

      it`s me again, back from a short vacation around easter holidays.

      After all those explanations in this thread I think it is really a CCS bug.

      The C-compiler and linker should be aware about the limitation of using an indirect offset bigger than 0x8000 in a CALLA instruction results in a negative sign extended address value. So either it should prepare the index register accordingly to offset this effect or use any of the other proposed workarounds.

      Just removing the "const" from the table places it in RAM at lower addresses, so the error does not appear.

      When I want the table in ROM, then I will use an additional step and hope that the compiler does not optimize the code too much. I didn't have the time yet to try this out, since at the same time I was chasing down a rare DMA error, which corrupted exactly this jump table in RAM. But that is an other story and I seem to have found my error there by now.

      I will try to produce a small sample code snippet. The current code is part of a larger state machine.

      Greetings,

      Jens

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jeff Tenney
      Posted by Jeff Tenney
      on Apr 11 2012 11:36 AM
      Guru10795 points

      Hi Jens,

      As JMG mentioned, you can select the small code model in CCS (if they still support it).

      That should make a nice work-around for your problem until they fix the bug.  In the small code model, CCS uses CALL instead of CALLA.

      Jeff

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • old_cow_yellow
      Posted by old_cow_yellow
      on Apr 11 2012 11:46 AM
      Guru25715 points

      Jens-Michael Gross
      ...
      Jeff Tenney
      I think this really is a CCS bug.
      Yes, it if was C code then indeed this is a bug in large code model (small code model won't use CALLA, and for CALL it works) ...

      Are you sure it won't use CALLA in small code model? (I do not have nor want to have CCS.)

      Jens-Michael Gross
      ...
      Jeff Tenney
      I'm guessing when he removes the "const" his code works just fine.
      Definitely, as the array then is copied to ram and I don't know any MSP with RAM above 0x8000 :) ...

      The OP showed code at 0x82xx and table at 0xC2xx (does not work). He also showed code at 0x8200 and table at 0x28xx (works). CC430F6137 has Flash from 0x8000 to 0xFFFF and RAM from 0x1A00 to 0x2BFF.

      Based on what the OP said, I must conclude that there is a hardware bug. I do not think the c-compiler caused the crash in this case.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • old_cow_yellow
      Posted by old_cow_yellow
      on Apr 11 2012 11:57 AM
      Guru25715 points

      Jeff Tenney

      Hi Jens,

      As JMG mentioned, you can select the small code model in CCS (if they still support it).

      That should make a nice work-around for your problem until they fix the bug.  In the small code model, CCS uses CALL instead of CALLA.

      Jeff

      That chip has only 32 KB Flash below 0x10000. Can he use large code model in CCS?

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jeff Tenney
      Posted by Jeff Tenney
      on Apr 11 2012 12:09 PM
      Guru10795 points

      old_cow_yellow
      That chip has only 32 KB Flash below 0x10000. Can he use large code model in CCS?

      Yes, I think so.  Somewhere I heard that CCS defaults to the large code model for any MCU with CPUX.  It's a waste of code space, stack space, etc, on MCUs with flash only up to 0xFFFF.

      Full disclosure, I don't actually use CCS either.  Just IAR.

      As to the bug, I think the OP's most-recent post summarized the problem pretty well.  CCS should know that indexes larger than 0x7FFF are treated as negatives when used with CALLA.  The effective address ends up at 0xFC272 instead of 0x0C272 as intended.

      Jeff

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 11 2012 13:35 PM
      Guru140135 points

      old_cow_yellow
      That chip has only 32 KB Flash below 0x10000. Can he use large code model in CCS?

      The CPU has the instructions, so the compiler generates it. Actually, the compiler doesn't know how much flash the MSP has. It may or may not have flash above 64k., This is the linkers job to know.

      Problem is that for large and small code model, you'll have to provide different versions of the standard library, different startup code etc. THis might be the reason if you cannot switch over to small code model for these CPUs. Less variants of the libraries needed.

      Jeff Tenney
      Full disclosure, I don't actually use CCS either.  Just IAR.

      I use neither. :)

      Jeff Tenney
      CCS should know that indexes larger than 0x7FFF are treated as negatives when used with CALLA.

      Yep, so it shouldn't use indexed CALLA at all, because only the linker will know what the final index will be. The compiler cannot make any assumption.

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens Potschadtke
      Posted by Jens Potschadtke
      on Apr 12 2012 03:08 AM
      Prodigy110 points

      Hello,

      below is a condensed code snippet to reproduce the described error:

      If one removes the "const" in the definition of functionList, then the table is placed in RAM and the error goes away.


      typedef void (fsmfunct) (void);         /*  Address of FSM function          */

      void func1(void);
      void func2(void);


      //the list of functions
      //if placed in ROM, the code crashes below
      fsmfunct * const functionList [] =
      {
          func1,
          func2,
          func1,
          func2
      };
      //a dummy counter
      int counter=0;


      //a dummy function
      void func1(void)
      {
        //do something
        counter++;
      }

      //a dummy function
      void func2(void)
      {
        //do something
        counter += 2;
      }


      void main(void)
      {
        int i;
       
        for (i=0;i<3;i++)
        {
          //call the function from the table
          (*functionList [i]) (); //crashes when table is in ROM
        }
       
      }


      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens Potschadtke
      Posted by Jens Potschadtke
      on Apr 12 2012 03:20 AM
      Prodigy110 points

      I found the workaround, which works for me: See below.

      The compiled code for calling entries from the table is now much more complicated and twice as big, but works.

      void main(void)
      {
        int i;
        fsmfunct *targetFunction;
        for (i=0;i<3;i++)
        {
          targetFunction = functionList [i]; //fetches address to R15
          (*targetFunction)(); //compiles to CALLA R15
         
        }
       
      }

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    • Jens-Michael Gross
      Posted by Jens-Michael Gross
      on Apr 12 2012 07:09 AM
      Guru140135 points

      Jens Potschadtke
      The compiled code for calling entries from the table is now much more complicated and twice as big, but works.

      Can you post the assembly code?

      Normally, it shouldn't differ from the original one much.

      Just one additional MOVX.A (just like I proposed). Unless, of course, the handling of function pointers in local variables is handled ineffective, using 2 16bit registers for the fetch (with MOV instructions) instead of a 20bit register, then combine them before the CALLA. But even if so, it's not a bug anymore :)

      _____________________________________
      Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.
      If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.

      Report Abuse
      • Reply
      You have posted to a forum that requires a moderator to approve posts before they are publicly available.
    12
    TI E2E™ Community
    • Support Forums
    • Blogs
    • Videos
    • Groups
    • Site Support & Feedback
    • Settings
    TI E2E™ Community Groups
    • TI University Program
    • Make the Switch
    • Microcontroller Projects
    • Motor Drive & Control
    Other Communities
    • Deyisupport
    • Designsomething.org
    • beagleboard.org
    • TI on Element 14
    • TI on TechXchangeSM
    Other Technical & Support Resources
    • WEBENCH® Design Center
    • Product Information Centers
    • Technical Documents
    • TI Design Network
    • TI Technical Articles
    • TI Training

    All content and materials on this site are provided "as is". TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with regard to these materials, including but not limited to all implied warranties and conditions of merchantability, fitness for a particular purpose, title and non-infringement of any third party intellectual property right. TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with respect to these materials. No license, either express or implied, by estoppel or otherwise, is granted by TI. Use of the information on this site may require a license from a third party, or a license from TI.

    Content on this site may contain or be subject to specific guidelines or limitations on use. All postings and use of the content on this site are subject to the Terms of Use of the site; third parties using this content agree to abide by any limitations or guidelines and to comply with the Terms of Use of this site. TI, its suppliers and providers of content reserve the right to make corrections, deletions, modifications, enhancements, improvements and other changes to the content and materials, its products, programs and services at any time or to move or discontinue any content, products, programs, or services without notice.

    Follow Us Texas Instruments on Facebook Texas Instruments on Twitter Texas Instruments on LinkedIn Texas Instruments on Google+
    TI Worldwide | Contact Us | my.TI Login | Site Map | Corporate Citizenship | mobile m.ti.com (Mobile Version)

    TI is a global semiconductor design and manufacturing company. Innovate with 100,000+ analog ICs and
    embedded processors, along with software, tools and the industry’s largest sales/support staff.

    © Copyright 1995-2013 Texas Instruments Incorporated. All rights reserved.
    Trademarks | Privacy Policy | Terms of Use