Cortex M4: инструкция cmp нарушена?

Это круто, и я чешу в затылке.

Настраивать:

  • Микроконтроллер 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, а это не равно нулю.

Я здесь в растерянности. Этот предсказатель ветвления стал мошенником? Инструменты сломаны? Я знаю лучше, чем винить инструменты, потому что это практически всегда моя вина, но мне трудно поверить, что процессор плохо себя ведет.


person CurtisHx    schedule 25.11.2020    source источник
comment
Очень странно. Убедитесь, что код микроконтроллера совпадает с кодом вашего теста. Очень маловероятно, что инструкция неисправна за пределами того, что указано в списке исправлений.   -  person fuz    schedule 25.11.2020
comment
вы подтвердили, что r3 не равно нулю?   -  person old_timer    schedule 26.11.2020
comment
что произойдет, если вы не используете отладчик и просто запустите код?   -  person old_timer    schedule 26.11.2020
comment
Прогнозирование ветвления не может повлиять на результаты cmp, которое было бы предсказанием значения для инструкций ALU. И предсказание ветвления или другие предположения не архитектурно видимы - пошаговое выполнение всегда должно приводить вас к правильной цели ветвления, а не умозрительное предположение.   -  person Peter Cordes    schedule 26.11.2020


Ответы (2)


Спасибо за все предложения. Я исправил проблему, обновив GCC до 9.3.1 и GDB до 9.2.

person CurtisHx    schedule 30.11.2020
comment
В большинстве случаев это не ошибка инструментальной цепочки, пока в редких случаях это не ошибка инструментальной цепочки :) - person Anton Krug; 21.06.2021

.thumb_func
.globl TEST0
TEST0:
    mov r0,#1
    mov r3,#1 
    uxtb r3,r3       
    and.w r3,r3,#1  
    cmp r3,#0        
    beq.n skip
    mov r0,#0
skip:
    bx lr

возвращает ноль, как ожидалось. На коре-м4. r3 не содержит того, что, по вашему мнению, в нем содержится. Попробуйте без отладчика.

Или вы каким-то образом делаете самомодифицирующийся код. Если вы думаете, что это предсказание ветвления (вы запускаете код в sram, затем меняете этот код и запускаете другой код в том же адресном пространстве). Добавить запись BPIALL

ldr r0,=0xE000EF78
str r0,[r0]

предсказание ветвления не выполняет ветвление, оно просто запускает предварительную выборку на несколько тактов раньше, если ветвление не происходит, оно не использует эти извлеченные инструкции.

Вы можете отключить прогнозирование ветвлений, если ваше ядро ​​даже поддерживает его (бит 18 регистра CCR). Тот, на котором я сейчас работаю, вы не можете установить этот бит, поэтому, похоже, он не поддерживается.

person old_timer    schedule 26.11.2020