Это круто, и я чешу в затылке.
Настраивать:
- Микроконтроллер ARM Cortex M4 (PAC5532).
- Отладчик Segger J-Link Plus.
- Компилятор GCC 7.2.0
- GDB 8.0.1
- Скомпилировано с -O0 (без оптимизации)
Вот код. Это часть логики противодействия входу GPIO. GPIO считывается с помощью функции pac5xxx_tile_register_read
. Вывод - это бит 0 в dinsig1
. Если 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 во время разборки. Инструкция cmp r3, #0
явно устанавливает флаг нуля, чего не должно быть. Потому что r3 равно 0x01
, а это не равно нулю.
Я здесь в растерянности. Этот предсказатель ветвления стал мошенником? Инструменты сломаны? Я знаю лучше, чем винить инструменты, потому что это практически всегда моя вина, но мне трудно поверить, что процессор плохо себя ведет.
cmp
, которое было бы предсказанием значения для инструкций ALU. И предсказание ветвления или другие предположения не архитектурно видимы - пошаговое выполнение всегда должно приводить вас к правильной цели ветвления, а не умозрительное предположение. - person Peter Cordes   schedule 26.11.2020