Перейти к содержанию
    

Переупорядочивание инструкций

12 минут назад, AHTOXA сказал:

Вот что у меня gcc выдал

Красиво GCC отработал:wink:

Однако, скорее всего, это результат везения))

Компилятор вправе перемещать любые операции, не изменяющие память, куда угодно, в том числе внутрь критической секции...

Об этом, собственно, эта тема изначально и появилась))

P.S. Этот приведенный листинг - это для моей функции без изменений/добавлений кода? На какой оптимизации?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я только удалил вызов reqTxDMA().

Оптимизация -O3.

Насчёт везения - я сомневаюсь. Но аргументированно сейчас спорить не готов, надо почитать доку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Интереса ради взял Ваши реализации __enable_irq()/__disable_irq() с клоббером - результат тот же корявый((

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 часов назад, Arlleex сказал:

Есть ли способ (кроме всяких пюре-асм) сказать компилятору, что между точками А и Б в коде нужно проводить только операции загрузки из памяти?

Думал уже ранее над это проблемой. И не раз. Решения не нашёл. Только ассемблер.  :unknw:

 

PS: А почему у Вас используется CPSIE I, вместо восстановления ранее сохранённого состояния PRIMASK? Вызов этой функции с запрещёнными прерываниями в принципе невозможен?

Но тогда MRS r0,PRIMASK - лишняя.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 часов назад, jcxz сказал:

Вызов этой функции с запрещёнными прерываниями в принципе невозможен?

Да, это единственное место во всем коде, где запрещаются прерывания, поэтому все так банально))

Цитата

Но тогда MRS r0,PRIMASK - лишняя.

Лишняя, но переписывать стандартный arm_compat.h мне совсем не хочется, поэтому бог с ним.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Коллеги, кто разбирается во встроенном асме. Прошу подсказать.

Я бы хотел изобразить следующее. Хорошо, я согласен написать свою реализацию участка с критической секцией. Однако, я хочу оперировать какими-то Си-шными адресами переменных, не задумываясь над тем, как будет получен этот самый адрес в регистрах (в Cortex-M0 весьма ограничены возможности по MOV).

Т.е. я хочу написать что-то типа

u32 volatile  REG;
u32 volatile *p;

__asm volatile ("ldr p, &REG");

а компилятор дальше разыграл эту LDR в нужную последовательность финальных команд (ну не хочу я втыкать в ограничения разных команд на Cortex-M0 относительно других). По аналогии с псевдокомандой ADR, короче.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделал вот так

if(len > 0) {
  u32 curRPos, curReqSize, curReqNDTR;
  __ASM volatile ("CPSID i          \n\t"
                  "ldr %[a], [%[b]] \n\t"
                  "ldr %[c], [%[d]] \n\t"
                  "ldr %[e], [%[f]] \n\t"
                  "CPSIE i" :
  [a] "=r" (curRPos),     [c] "=r" (curReqSize),     [e] "=r" (curReqNDTR) :
  [b] "r"  (TxFIFO.rpos), [d] "r"  (TxFIFO.reqSize), [f] "r"  (DMA1_Channel4->CNDTR));
  
  ...

получил

_ZN6nsUART11writeTxFIFOEPhj
        0x08002e98:    b5f0        ..      PUSH     {r4-r7,lr}
        0x08002e9a:    b085        ..      SUB      sp,sp,#0x14
        0x08002e9c:    460c        .F      MOV      r4,r1
        0x08002e9e:    2100        .!      MOVS     r1,#0
        0x08002ea0:    2c00        .,      CMP      r4,#0
        0x08002ea2:    d022        ".      BEQ      0x8002eea ; _ZN6nsUART11writeTxFIFOEPhj + 82
        0x08002ea4:    9103        ..      STR      r1,[sp,#0xc]
        0x08002ea6:    9004        ..      STR      r0,[sp,#0x10]
        0x08002ea8:    4b2b        +K      LDR      r3,[pc,#172] ; [0x8002f58] = 0x200002d4
        0x08002eaa:    6818        .h      LDR      r0,[r3,#0]
        0x08002eac:    2143        C!      MOVS     r1,#0x43
        0x08002eae:    008f        ..      LSLS     r7,r1,#2
        0x08002eb0:    59d9        .Y      LDR      r1,[r3,r7]
        0x08002eb2:    4a65        eJ      LDR      r2,[pc,#404] ; [0x8003048] = 0x40020044
        0x08002eb4:    6852        Rh      LDR      r2,[r2,#4]
        0x08002eb6:    b672        r.      CPSID    i
        0x08002eb8:    6800        .h      LDR      r0,[r0,#0]
        0x08002eba:    6809        .h      LDR      r1,[r1,#0]
        0x08002ebc:    6812        .h      LDR      r2,[r2,#0]
        0x08002ebe:    b662        b.      CPSIE    i
        0x08002ec0:    1840        @.      ADDS     r0,r0,r1
        0x08002ec2:    1a82        ..      SUBS     r2,r0,r2
        0x08002ec4:    20ff        .       MOVS     r0,#0xff
        0x08002ec6:    43c0        .C      MVNS     r0,r0
        0x08002ec8:    2aff        .*      CMP      r2,#0xff


Не знаю только, насколько это все написано корректно с точки зрения inline asm.

P.S. Нет, фигня полная, судя по листингу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 часов назад, Arlleex сказал:

Да, это единственное место во всем коде, где запрещаются прерывания

Сильно!  :bb::good:

2 часа назад, Arlleex сказал:

Коллеги, кто разбирается во встроенном асме. Прошу подсказать.

Могу привести (в качестве примера) Вам мою реализацию семейства функций атомарного сравнения-обмена (на inline asm):

#define ATOMIC_MANNER   2  //==0 - функции Atomic...() реализованы на критических секциях
                           //==1 - функции Atomic...() реализованы на механизме эксклюзивного доступа используя intrinsic-функции семейства __LDREX()/__STREX()
                           //==2 - функции Atomic...() реализованы на механизме эксклюзивного доступа используя команды семейства LDREX/STREX в asm()-вставках
                           //==3 - то же, что и ==2, но не создаются отдельные варианты функций для непосредственных значений последнего аргумента (для компиляции с уровнем оптимизации <Medium)

#if ATOMIC_MANNER == 2
#define IMM_ARG "i"
#else
#define IMM_ARG "r"
#endif

#define CREATE_AtomicCmpSwp(typ, imm)      \
{                                          \
  u32 r, i;                                \
  asm(                                     \
    "p01: LDREX" typ  "   %0, [%2]    \n"  \
    "     CMP      %0, %4             \n"  \
    "     ITT      EQ                 \n"  \
    "     STREX" typ "EQ %1, %3, [%2] \n"  \
    "     CMPEQ    %1, #1             \n"  \
    "     BEQ      p01"                    \
    : "=&r"(r), "=&r"(i)                   \
    : "r"(ptr), "r"(newVal), imm(cmpVal)   \
    : "cc", "memory");                     \
  i = i;                                   \
  return r;                                \
}

#pragma inline = forced
inline u32 AtomicCmpSwp(u8 volatile *ptr, u32 newVal, u32 cmpVal) CREATE_AtomicCmpSwp("B", "r")
#pragma inline = forced
inline u32 AtomicCmpSwpI(u8 volatile *ptr, u32 newVal, u32 cmpVal) CREATE_AtomicCmpSwp("B", IMM_ARG)
#pragma inline = forced
inline u32 AtomicCmpSwp(u16 volatile *ptr, u32 newVal, u32 cmpVal) CREATE_AtomicCmpSwp("H", "r")
#pragma inline = forced
inline u32 AtomicCmpSwpI(u16 volatile *ptr, u32 newVal, u32 cmpVal) CREATE_AtomicCmpSwp("H", IMM_ARG)
#pragma inline = forced
inline u32 AtomicCmpSwp(u32 volatile *ptr, u32 newVal, u32 cmpVal) CREATE_AtomicCmpSwp("", "r")
#pragma inline = forced
inline u32 AtomicCmpSwpI(u32 volatile *ptr, u32 newVal, u32 cmpVal) CREATE_AtomicCmpSwp("", IMM_ARG)

Кому другому я бы не стал такое приводить, но вы думаю - разберётесь в хитросплетениях.  :wink:

Приведённый код - он только для ATOMIC_MANNER=2 и для ATOMIC_MANNER=3. Для 0 и 1 - другие ветки кода, которых тут нет.

 

PS: Обратите внимание на префиксы для принимаемых аргументов и возвращаемых значений. А также на "memory".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если вдруг кому интересно, на всякий случай, выкладываю итоговый вариант

Спойлер
s32 writeTxFIFO(u8 src[], u32 len) {
  if(len > 0) {
    u32 curRPos, curReqSize, curReqNDTR;
    
    asm volatile (
      "cpsid i        \n\t"
      "ldr   %0, [%3] \n\t"
      "ldr   %1, [%4] \n\t"
      "ldr   %2, [%5] \n\t"
      "cpsie i        \n\t"
      
      : "=&r" (curRPos),
        "=&r" (curReqSize),
        "=&r" (curReqNDTR)
      
      : "r"   (&TxFIFO.rpos),
        "r"   (&TxFIFO.reqSize),
        "r"   (&DMA1_Channel4->CNDTR)
      
      : "memory"
    );
    
    u32 const bufSize = FIFO_TX_SIZE;
    u32       nxtRPos = curRPos + curReqSize - curReqNDTR;
    
    if(nxtRPos >= bufSize)
      nxtRPos -= bufSize;
    
    u32 const curWPos = TxFIFO.wpos;
    u32       freeLen = nxtRPos;
    
    if((s32)(freeLen -= curWPos) <= 0)
      freeLen += bufSize;
    
    if(freeLen - 1 >= len) {
      u32 llen    = 0, rlen = len,
          nxtWPos = curWPos + len;
      
      if(nxtWPos >= bufSize)
        nxtWPos -= bufSize,
        llen     = nxtWPos,
        rlen    -= llen;
      
      memcpy(&TxFIFO.buf[curWPos], src, rlen);
      
      if(llen > 0)
        memcpy(TxFIFO.buf, &src[rlen], llen);
      
      TxFIFO.wpos = nxtWPos;
      
      if(!TxFIFO.isStart)
        TxFIFO.isStart = true,
        reqTxDMA(&TxFIFO.buf[curWPos], rlen);
    }
    else return -1;
  }
  
  return 0;
}


Теперь получил, что написал - максимально короткую критическую секцию длиной в 3 инструкции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...