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.

[参考译文] MSP430FR2433:勘误表 CPU40影响 GCC、具体取决于数据中的第一项。 (如果全局变量具有一些值、则生成无效代码)

Guru**** 2540720 points
Other Parts Discussed in Thread: MSP430-GCC-OPENSOURCE, MSP430FR2433

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1200316/msp430fr2433-errata-cpu40-impacts-gcc-depending-on-first-item-in-data-invalid-code-generated-if-global-variable-has-some-values

器件型号:MSP430FR2433
主题中讨论的其他器件:MSP430-GCC-OPENSOURCE

MSP430-GCC-OPENSOURCE 编译器有一个关于全局变量的看似奇怪的行为(有时)。

附件中的示例项目是来自我一直使用的代码库的简化示例。 在"twi.c"文件中、有一个名为"myvar"的全局变量。 当用一些值(0x0040、0x0140、0x0240、...)初始化该变量时 0x0F40)生成的程序被"破坏"。

BROKEN 意味着(使用调试器确定):

  • 该程序从不执行到 main
  • 程序按预期达到__ crt0_start
  • 程序会将其添加到__ crt0_init_BSS 中的调用指令
  • 然后程序在地址0x0004 (PC = 0x0004)结束、这是一个到自身的跳转
  • 在0x0004的调用和首次到达之间有516、095个时钟周期(非即时跳转)

令人困惑的是、访问全局变量的看门狗 ISR (请参阅"wiring.c")也是代码"broked"所必需的。

重现步骤(使用 BugExample.zip)

  • 将 BugExample 项目导入 CCS
  • 确保看门狗 ISR 在 wiring.c 中增加"WDT_overflow_count"
  • 确保在 twi.c 中将一个"broked"值分配给"myvar"(请见针对被破坏和工作值的注释)
  • 清理和构建工程
  • 开始调试会话
  • 请注意、程序从未使其成为 main

如果"myvar"不是损坏的值之一、或者如果 WDT ISR 不递增(访问?)、程序将按预期工作 "wDT_overflow_count"。

移植到 TI 编译器的相同程序(也作为 BugExampleTI.zip 随附)不会发生这种情况

e2e.ti.com/.../BugExample.zipe2e.ti.com/.../BugExampleTI.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更改已初始化变量的值对生成的代码没有任何作用。 在调用 memset ()(以清除 BSS )之后对 memcopy ()的调用保持不变。 只有复制的数据才会更改。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我最初的描述有点不准确。 除了数据段中的值之外、实际生成的程序是相同的(基于使用 objdump -ds 反汇编的差异)。

    但是、当数据段包含一个"坏"值 memset 时、似乎会断开。 对_crt0_init_BSS 中 memset 的调用从不返回。 经过大约500、000个时钟周期后、PC 最终值为4。 这似乎是一个 memset 错误。

    为什么应该为零的 memset 调用会受到数据段中的值的影响、这仍然没有道理、但似乎是这样。 更令人困惑的是、在这个特定值中、高4位为零、低8位为0x40 (位8-11似乎无关紧要)。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    为了进一步增加我的困惑:

    • 我无法在 FR2355上复制此示例(FR2433特定的问题?)
    • 在"myvar"下面的 twi.c 中添加一个具有"良好"值的变量可以防止出现该问题

    也许它在某种程度上与0x2000处的值相关(根据反汇编、这是 myvar 位于数据段的位置)。 添加第二个全局变量会将 myvar 下拉至0x2002 (从而防止发生该问题)。

    我仍不确定 WDT 中断访问全局变量的关系、但禁用看起来会使一切正常工作、无论是否有数据。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很抱歉回复很快。 只是继续寻找其他的东西,因为我搞错了。 我现在已经在一个简单得多的项目中复制了它。 我目前的理论如下

    在以下一组情况下初始化 BSS 时、MSP430FR2433 memset 上不知何故出现错误

    • BSS 中必须有某个值才能导致调用 memset
    • 数据(0x2000)中的第一个项必须具有值0x0_40、其中_可以是任何数字

    0x2002而不是0x2000上的0x0_40不会发生这种情况。

    无论0x2000处的值如何、当 BSS 为空时都不会发生这种情况(可能是因为永远不会调用 memset)。

    鉴于 memset 应该非常简单、我想知道这是否与硬件相关。

    编辑:附加了演示该问题的更简单项目。

    e2e.ti.com/.../6102.ReducedExample.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    您是否从 GCC 编译器和 TI 编译器输出了.txt 或.hex 文件、并对这两个文件进行了比较?

    此致、

    现金 Hao

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    memset 很简单:

    0000c404 <__crt0_init_bss>:
        c404:       3c 40 02 20     mov     #8194,  r12     ;#0x2002
    
    0000c408 <.Loc.76.1>:
        c408:       0d 43           clr     r13             ;
    
    0000c40a <.Loc.77.1>:
        c40a:       3e 40 04 00     mov     #4,     r14     ;
    
    0000c40e <.Loc.81.1>:
        c40e:       b0 12 ea c4     call    #-15126 ;#0xc4ea
    
    
    000c4ea <memset>:
        c4ea:       0e 5c           add     r12,    r14     ;
    
    0000c4ec <.LVL2>:
        c4ec:       0f 4c           mov     r12,    r15     ;
    
    0000c4ee <L0^A>:
        c4ee:       0f 9e           cmp     r14,    r15     ;
        c4f0:       01 20           jnz     $+4             ;abs 0xc4f4
    
    0000c4f2 <.Loc.104.1>:
        c4f2:       30 41           ret                     
    
    0000c4f4 <.L3>:
        c4f4:       1f 53           inc     r15             ;
    
    0000c4f6 <.LVL4>:
        c4f6:       cf 4d ff ff     mov.b   r13,    -1(r15) ; 0xffff
        c4fa:       f9 3f           jmp     $-12            ;abs 0xc4ee
    

    而完全不关心存储器中的数据是什么。 请注意、memset 包括 零长度 BSS 校验。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    仔细查看链接器文件(gcc)、看起来数据直接放在 FRAM 中的文本之后。 在此程序中、内存集被放置在文本的末尾并且以一个跳转指令结束。 因此、数据中的第一项能够导致勘误表 CPU40中所述的问题。

    勘误表将 gcc 列为不受影响、但我认为在此特定场景中(文本末尾的 memset)、数据中的第一项可能会导致问题。

    这不会影响 FR2355、因为持久段位于文本和数据之间(不过、这可能仍然是问题、具体取决于持久段中的首要内容)。

    我可以考虑的解决方法涉及修改链接器脚本。

    • 将 keep (*(.text.end_of_text))添加到文本段、并将一个函数添加到此段、其变为"nop"和"ret"
    • 在文本和数据之间添加一个段、并在其中放置一个变量、该变量是 NOP 指令的数据。

    我真的不喜欢这些解决方案中的任何一个(因为我的代码库最终将支持许多目标、并且维护已修改的链接器文件似乎很混乱)。 但是、我没有看到可确保不会出现问题的其他解决方案。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果 GCC 认为需要、它将插入一个 NOP。 但它无法处理库函数 memset 的特殊结构。 它在中间有其返回指令、在末尾有一个分支 编译器无法修复它。 链接器如果感兴趣、也可能需要链接。

    这个问题要求 memset 成为文本段中代码的最后一位、并且对于初始化程序中的第一个数据位、应该具有特定的模式。 简单的做法是对已初始化的数据执行一些操作。 您可以向链接器脚本添加一些内容(有一种包含数据的机制)、但更简单的是修复初始化程序。 改变变量的顺序最简单。 在最坏的情况下添加"int foo = 0;"、这样就不会触发该勘误表。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我已经成功修改了链接器脚本。 在文本部分之后添加以下内容(0x4303是一个"NOP")

    .fix_cpu40 :
    {
      . = ALIGN(2);
      SHORT(0x4303);
    } > FRAM

    不幸的是,我正在使用的代码库是基于 Arduino 这意味着对构建系统和链接顺序有非常最小的控制,所以修复初始化程序的简单选项不会可靠地工作。

    这种方法的缺点(我可以想到)是当这些条件不满足时 FRAM 中浪费了一个字的空间、并且我必须使用经过修改的链接器脚本而不是与编译器包一起分发的脚本、但这些缺点在我的用途中是可以接受的。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    关于初始化数据的位置、我听到了一点提示、但我不知道是什么。 然后、当我查看针对另一个处理器(fr5969)的代码时、我注意到这些数据位于 FRAM 的开头。 而非.text 段前面的符号链接。

    我查看了链接器脚本、但我对它们不是专家、也看不到任何会导致这种情况的脚本。