首页 > 解决方案 > Cortex M4: cmp instruction broken?

问题描述

This one's a doozy and I'm scratching my head.

Setup:

Here's the code. It's part of the debounce logic for a GPIO input. The GPIO is read via the pac5xxx_tile_register_read function. The pin is bit 0 in dinsig1. If dinsig is 0x01, that means the GPIO is high. If dinsig is 0x00, the GPIO is low.

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;

The if ((dinsig1 & 0x01) != 0) instruction is the one causing problems. The code will correctly run until the GPIO goes from high to low, and then low to high (dinsig goes from 0x01 to 0x00 to 0x01). dinsig always reads accurately, but if ((dinsig1 & 0x01) != 0) evaluates to true.

Here's the disassembly for the if ((dinsig1 & 0x01) != 0) statement.

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.

I'm watching the ASPR register register while stepping through the disassembly. The cmp r3, #0 instruction clearly sets the Zero flag, which it should not. Because r3 is 0x01, and that is not equal to zero.

I'm at a loss here. Is this a branch predictor gone rogue? Tools broken? I know better than to blame the tools because it's virtually always my fault, but I find it hard to believe the CPU is misbehaving.

标签: assemblyarmcortex-mbranch-prediction

解决方案


感谢所有的建议。我通过将 GCC 更新到 9.3.1 和 GDB 到 9.2 解决了这个问题


推荐阅读