STM32 такой же, пока l oop код, но скомпилированный с другим кодом сборки - PullRequest
2 голосов
/ 17 марта 2020

Я изучаю RTOS на плате stm32F411RE (Cortex-M4). Я использую MDK uVision v5. Я столкнулся с проблемой C код при l oop. Следующий код точно такой же в моем проекте и проекте инструктора (на Udemy), однако после компиляции обоих проектов (на моем P C) код сборки выглядит иначе. Я хочу спросить, что отличает это. Спасибо.

void osSignalWait(int32_t *semaphore)
{
    __disable_irq();
    while(*semaphore <=0)
    {       
            __disable_irq();        
            __enable_irq();
    }
    *semaphore -= 0x01;
    __enable_irq();
}

В режиме отладки (см. Изображение), если условие не совпадает, go не загружает реальное значение LDR r1, [r0, # 0x00 ] и затем сделайте сравнение. Вместо этого он сравнивает и выполняет команду внутри while l oop. My code compiled debug view Мой код, скомпилированный ниже

   100: void osSignalWait(int32_t *semaphore) 
   101: { 
0x08001566 4770      BX            lr
   102:         __disable_irq(); 
   103:         while(*semaphore <=0) 
   104:         {               
0x08001568 B672      CPSID         I
   101: { 
   102:         __disable_irq(); 
   103:         while(*semaphore <=0) 
   104:         {               
0x0800156A 6801      LDR           r1,[r0,#0x00]
0x0800156C E001      B             0x08001572
   105:                         __disable_irq();                 
0x0800156E B672      CPSID         I
   106:                         __enable_irq(); 
   107:         } 
   108:         *semaphore -= 0x01; 
0x08001570 B662      CPSIE         I
0x08001572 2900      CMP           r1,#0x00
0x08001574 DDFB      BLE           0x0800156E
0x08001576 1E49      SUBS          r1,r1,#1
   109:         __enable_irq(); 
0x08001578 6001      STR           r1,[r0,#0x00]
0x0800157A B662      CPSIE         I
   110: } 

Если я скомпилирую код инструктора (в Udemy) (в моем P C, используя его проект), код ассемблера будет другим ( с точно таким же, пока код l oop). Он снова загрузит реальное значение и сделает сравнение. Instructor's code compiled debug view Код инструктора, скомпилированный ниже (Скомпилировано на моем P C)

100: void osSignalWait(int32_t *semaphore) 
   101: { 
0x08000CDE 4770      BX            lr
   102:         __disable_irq(); 
0x08000CE0 B672      CPSID         I
   103:         while(*semaphore <=0) 
   104:         { 
0x08000CE2 E001      B             0x08000CE8
   105:                         __disable_irq();                         
0x08000CE4 B672      CPSID         I
   106:                         __enable_irq();   
   107:         } 
0x08000CE6 B662      CPSIE         I
0x08000CE8 6801      LDR           r1,[r0,#0x00]
0x08000CEA 2900      CMP           r1,#0x00
0x08000CEC DDFA      BLE           0x08000CE4
   108:         *semaphore -= 0x01; 
0x08000CEE 6801      LDR           r1,[r0,#0x00]
0x08000CF0 1E49      SUBS          r1,r1,#1
0x08000CF2 6001      STR           r1,[r0,#0x00]
   109:         __enable_irq(); 
   110:          
   111:          
0x08000CF4 B662      CPSIE         I
   112: } 

Ответы [ 2 ]

2 голосов
/ 17 марта 2020

Поскольку вы не говорите компилятору semaphore может измениться во время выполнения этой функции, ваш компилятор решил оптимизировать ваш код и загрузить значение семафора только один раз и использовать его копию в то время как l oop , тогда только напишите результат в конце. Как написано сейчас, у компилятора нет причин предполагать, что это может быть вредно.

Чтобы уведомить компилятор о переменной , может измениться вне функции во время выполнения этой функции, используйте ключевое слово volatile, см. https://en.cppreference.com/w/c/language/volatile

В этом случае ваш код станет:

void osSignalWait(volatile int32_t *semaphore)
{
    __disable_irq();
    while(*semaphore <=0)
    {       
        __disable_irq();        // Note: I think the order is wrong...
        __enable_irq();
    }
    *semaphore -= 0x01;
    __enable_irq();
}

Кстати, позвонив по номеру __disable_irq дважды (один раз до того, как l oop, затем в начале внутри l oop), затем __enable_irq кажется немного странным, разве вы не хотите включить (и сделать что-то), а затем отключить в течение времени, пока l oop

0 голосов
/ 17 марта 2020

Это очень хорошо известная ошибка оптимизации. Сообщили много раз. Имея клоббер памяти, он должен каждый раз читать память.

Вот пример того, как работают клобберы

#include <stdint.h>

unsigned x;
volatile unsigned y;


int foo()
{
    while(x < 1000);
}

int bar()
{
    while(x < 1000) asm("":::"memory");
}
foo:
        ldr     r3, .L5
        ldr     r3, [r3]
        cmp     r3, #1000
        bxcs    lr
.L3:
        b       .L3
.L5:
        .word   x
bar:
        ldr     r1, .L11
        ldr     r2, .L11+4
        ldr     r3, [r1]
        cmp     r3, r2
        bxhi    lr
.L9:
        ldr     r3, [r1]
        cmp     r3, r2
        bls     .L9
        bx      lr
.L11:
        .word   x
        .word   999
...