【发布时间】:2021-03-08 16:46:42
【问题描述】:
这是一个笨蛋,我正在摸不着头脑。
设置:
- ARM Cortex M4 微控制器 (PAC5532)。
- Segger J-Link Plus 调试器。
- GCC 7.2.0 编译器
- GDB 8.0.1
- 使用 -O0 编译(无优化)
这是代码。它是 GPIO 输入的去抖动逻辑的一部分。 GPIO 通过pac5xxx_tile_register_read 函数读取。该引脚是dinsig1 中的位0。如果dinsig 为0x01,则表示GPIO 为高电平。如果dinsig 为0x00,则GPIO 为低电平。
static uint32_t triggerDebounce = 0;
volatile uint8_t dinsig1 = pac5xxx_tile_register_read(ADDR_DINSIG1);
if ((dinsig1 & 0x01) != 0) //This is the problem line.
triggerDebounce = (triggerDebounce << 1);
else
triggerDebounce = (triggerDebounce << 1) | 1;
if ((dinsig1 & 0x01) != 0) 指令是导致问题的指令。代码将正确运行,直到 GPIO 从高到低,然后从低到高(dinsig 从 0x01 到 0x00 到 0x01)。 dinsig 总是准确读取,但 if ((dinsig1 & 0x01) != 0) 评估为真。
这是if ((dinsig1 & 0x01) != 0) 语句的反汇编代码。
0x00004268 ldrb r3, [r7, #7] ;Loads dinsig into r3.
0x0000426a uxtb r3, r3 ;Expands dinsig 3 into a 32 bit word.
0x0000426c and.w r3, r3, #1 ;ANDs dinsig 3 with 0x01 and stores result in r3
0x00004270 cmp r3, #0 ;Compares r3 with 0
0x00004272 beq.n 0x4280 <IsTriggerPressed+40> ; Jumps to address 0x4280 if the ZERO flag is set.
我在逐步进行反汇编时正在查看ASPR register 寄存器。 cmp r3, #0 指令清楚地设置了零标志,它不应该这样做。因为r3是0x01,不等于0。
我在这里不知所措。这是一个分支预测器流氓吗?工具坏了?我知道最好不要责怪这些工具,因为这几乎总是我的错,但我很难相信 CPU 行为不端。
【问题讨论】:
-
很奇怪。确保微控制器上的代码与您的测试代码相同。超出勘误表所述的指令不太可能存在缺陷。
-
您已确认 r3 不为零?
-
如果您不使用调试器而只运行代码会发生什么?
-
分支预测不会影响
cmp的结果,这将是 ALU 指令的值预测。并且分支预测或其他推测在架构上不可见 - 单步执行应该始终将您带到正确的分支目标,而不是推测性的猜测。
标签: assembly arm cortex-m branch-prediction