Warm tip: This article is reproduced from serverfault.com, please click

Cortex M4: cmp instruction broken?

发布于 2020-11-25 19:11:04

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

Setup:

  • ARM Cortex M4 microcontroller (PAC5532).
  • Segger J-Link Plus debugger.
  • GCC 7.2.0 compiler
  • GDB 8.0.1
  • Compiled with -O0 (no optimizations)

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.

Questioner
CurtisHx
Viewed
0
CurtisHx 2020-11-30 20:47:39

Thanks for all the suggestions. I fixed the issue by updating GCC to 9.3.1 and GDB to 9.2