Arlleex 183 21 марта, 2023 Опубликовано 21 марта, 2023 · Жалоба 12 минут назад, AHTOXA сказал: Вот что у меня gcc выдал Красиво GCC отработал Однако, скорее всего, это результат везения)) Компилятор вправе перемещать любые операции, не изменяющие память, куда угодно, в том числе внутрь критической секции... Об этом, собственно, эта тема изначально и появилась)) P.S. Этот приведенный листинг - это для моей функции без изменений/добавлений кода? На какой оптимизации? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 21 марта, 2023 Опубликовано 21 марта, 2023 · Жалоба Я только удалил вызов reqTxDMA(). Оптимизация -O3. Насчёт везения - я сомневаюсь. Но аргументированно сейчас спорить не готов, надо почитать доку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 21 марта, 2023 Опубликовано 21 марта, 2023 · Жалоба Интереса ради взял Ваши реализации __enable_irq()/__disable_irq() с клоббером - результат тот же корявый(( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 21 марта, 2023 Опубликовано 21 марта, 2023 · Жалоба 6 часов назад, Arlleex сказал: Есть ли способ (кроме всяких пюре-асм) сказать компилятору, что между точками А и Б в коде нужно проводить только операции загрузки из памяти? Думал уже ранее над это проблемой. И не раз. Решения не нашёл. Только ассемблер. PS: А почему у Вас используется CPSIE I, вместо восстановления ранее сохранённого состояния PRIMASK? Вызов этой функции с запрещёнными прерываниями в принципе невозможен? Но тогда MRS r0,PRIMASK - лишняя. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 22 марта, 2023 Опубликовано 22 марта, 2023 · Жалоба 11 часов назад, jcxz сказал: Вызов этой функции с запрещёнными прерываниями в принципе невозможен? Да, это единственное место во всем коде, где запрещаются прерывания, поэтому все так банально)) Цитата Но тогда MRS r0,PRIMASK - лишняя. Лишняя, но переписывать стандартный arm_compat.h мне совсем не хочется, поэтому бог с ним. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 22 марта, 2023 Опубликовано 22 марта, 2023 · Жалоба Коллеги, кто разбирается во встроенном асме. Прошу подсказать. Я бы хотел изобразить следующее. Хорошо, я согласен написать свою реализацию участка с критической секцией. Однако, я хочу оперировать какими-то Си-шными адресами переменных, не задумываясь над тем, как будет получен этот самый адрес в регистрах (в Cortex-M0 весьма ограничены возможности по MOV). Т.е. я хочу написать что-то типа u32 volatile REG; u32 volatile *p; __asm volatile ("ldr p, ®"); а компилятор дальше разыграл эту LDR в нужную последовательность финальных команд (ну не хочу я втыкать в ограничения разных команд на Cortex-M0 относительно других). По аналогии с псевдокомандой ADR, короче. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 22 марта, 2023 Опубликовано 22 марта, 2023 · Жалоба Сделал вот так 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. Нет, фигня полная, судя по листингу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 22 марта, 2023 Опубликовано 22 марта, 2023 · Жалоба 7 часов назад, Arlleex сказал: Да, это единственное место во всем коде, где запрещаются прерывания Сильно! 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) Кому другому я бы не стал такое приводить, но вы думаю - разберётесь в хитросплетениях. Приведённый код - он только для ATOMIC_MANNER=2 и для ATOMIC_MANNER=3. Для 0 и 1 - другие ветки кода, которых тут нет. PS: Обратите внимание на префиксы для принимаемых аргументов и возвращаемых значений. А также на "memory". 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 22 марта, 2023 Опубликовано 22 марта, 2023 · Жалоба Кое-что себе взял из синтаксиса, спасибо) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 3 апреля, 2023 Опубликовано 3 апреля, 2023 · Жалоба Если вдруг кому интересно, на всякий случай, выкладываю итоговый вариант Спойлер 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 инструкции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться