Jump to content

    

Rst7

Модераторы
  • Content Count

    4481
  • Joined

  • Last visited

Everything posted by Rst7


  1. И вот это они зря на откуп реализации отдали, да. Вот, например, я приводил пример кода, который дергает блок из списка, а добавить блок в этот список малость усложняется - сначала надо обычным чтением прочитать указатель на голову, заполнить им поле next в блоке, а затем уже после LDREX указателя на голову проверить, что он не изменился (и если изменился, то сделать CLREX и начинать сначала), и только после этого сохранить указатель на новый блок. Походу, и доставание блока из списка тоже должно выглядеть по другому. Сначала берем p, и p->next, а уже потом LDREX/STREX. Некрасиво, но действительно portable.
  2. Ну? Про локальный сказано, что он может либо адрес отслеживать, либо только выполнение LDREX/STREX. Т.е. STR в произвольный адрес не приведет к сбросу монитора. В общем произвольный STR не в мониторящийся адрес безопасен между LDREX/STREX. А вот зачем этот идиотизм со сбросом монитора при эксепшне - мне нифига непонятно. От него только хуже.
  3. С чего бы? Просто в C-M таки эксепшн сбрасывает монитор. Но только в -M Суть. Глобальный - он для многопроцессорной системы. Кроме того, все равно запись в тот же адрес нужна, а не произвольный STR.
  4. Верно описывает результат только для Cortex-M. Потому что объяснение неверное. А зачем писать в переменную, к которой Вы организуете эксклюзивный доступ, обычным способом? Только менее универсальный. Например, взять элемент из списка на ARM выглядит так: #define ExAddr(VAL) ((volatile unsigned int *)(&(VAL))) typedef struct LLITEM { struct LLITEM *next; unsigned char data[100]; }LLITEM; volatile LLITEM *FreeBlocks; LLITEM *AllocBlock(void) { LLITEM *p; LLITEM *next; do { p=(LLITEM*)__LDREX(ExAddr(FreeBlocks)); if (!p) {__CLREX(); return p;} next=p->next; }while(__STREX((unsigned long)next,ExAddr(FreeBlocks))); return p; } А на x86 с его единственным lock'ом надо извращаться.
  5. Кстати, это только к Cortex-M относится, всякие -А вроде не сбрасывают.
  6. Я не об этом. Обычная запись в память (или чтение) между LDREX/STREX не сбрасывает флаг. volatile unsigned int testvar; volatile unsigned int testvar2; void TestEX(void) { unsigned int tv; tv=__LDREX(&testvar); __no_operation(); __no_operation(); __no_operation(); testvar2=1; testvar2; __no_operation(); __no_operation(); __no_operation(); tv=__STREX(tv,&testvar); DEBUG_PRINTF("__STREX result %d\r\n",tv); } Такой код печатает "__STREX result 0", несмотря на наличие LDR/STR между LDREX/STREX. То, что заход в прерывания сбрасывают флаг- это какой-то отдельный тонкий момент, с ним надо разбираться, потому что в теории так быть не должно. Ага, вот в чем дело (из мануала на CM4) Т.к. прерывания - это тоже эксепшн, то вот и ответ.
  7. Например непонимание работы exclusive monitor'а ядра тут:
  8. Какие-то очень сложные у вас всех TFTP. У меня от LPC1768 загрузчик весит Из которых 1132 байта - это библиотечный printf, который можно выбросить, если сильно прижмет. Кстати, я его где-то выкладывал тут.
  9. USB-стек в МК

    *facepalm.jpg*
  10. USB-стек в МК

    Там все хуже, там просто не работает. Виснет намертво сразу.
  11. Очень жаль, что участник нашего форума оказался таким провальным. Если бы он это все высказывал тут в дискуссиях - то пофиг. А вот то, что он это несет в неокрепшие умы (я же не просто так цитату принес) - вот за это нет прощения.
  12. USB-стек в МК

    Давайте, кстати, проверим на вшивость Ваш прекрасный дорогой софт. Что у Вас в заголовочнике с регистрами от RT1020 описано для USB_USBCMD_ATDTW_MASK и USB_USBCMD_ATDTW_SHIFT?
  13. USB-стек в МК

    А причем тут "слабый софт"? Это зачем мне чужой код осваивать? Я за свое могу нести ответственность, а за чужое - пардон. Чтобы за чужое нести ответственность - надо его досконально изучить, а это сравнимо с написанием своего.
  14. Там еще и дичь про LDREX/STREX написана. Я бы вообще дал этому дьяволу по лицу. Именно за вот это:
  15. USB-стек в МК

    Вот прям могу с пылу с жару рассказать про борьбу с USB-стеком. Камень - iMX RT1020. Имею принцип в жизни - писать самому, готовое не использовать, максимум - подглядеть в примеры какие-то опущенные в даташитах подробности. Я не особо часто бодался с USB, последний раз лет эдак 15 назад делал эмулятор FT232 на AT90USB162. А теперь пришлось сделать ECM/RNDIS устройство. Официальные примеры для этих iMX RT есть, но со страшным нагромождением уровней абстракции, разбросано по куче файлов, местами - плюсы на Си врукопашную, в общем - все прелести. Довольно быстро все поехало в простом варианте типа суперцикла, без всяких прерываний, просто с проверкой флагов. Затем начал переделывать на вменяемую работу, т.е. прерывания, обеспечение zero copy, минимальные простои и так далее. И в конце концов наступил на мертвое зависание алгоритма добавления нового буфера в цепочку буферов USB DMA на ходу. Алгоритм описан в даташите, более того, именно его реализацию (не без индусских делов) я обнаружил при изучении примеров (после того, как моя реализация не заработала). Убито было несколько дней. Оказалось, что в заголовочном файле с регистрами периферии был неверно описан один из битов в регистрах (не 1<<14, а 1<<12). Обнаружил это совершенно случайно, когда уже начал проверять совсем все. Заголовочный файл с регистрами был взят именно из официальных примеров. Так что официальные примеры, конечно, компилируются, но вот никто их на таргете никогда не запускал и не проверял. Вообще оказалось, что во всей этой iMX-линейке вроде бы и один и тот же USB, но этот бит пляшет произвольно от типа к типу, в каких-то - 12й, в каких-то - 14й, в некоторых это считалось ошибкой и описано в errata, в некоторых нет, в общем - полный хаос. Это в общем я к тому, что взяв "готовый" можно влететь крепко с точки зрения "я возьму готовый, сэкономлю дофига времени". Ну и да, по итогу весь этот RNDIS у меня - один сишный файл вполне обозримых размеров. С минимумом оверхэда, как я люблю.
  16. Я - никак не делаю, живу жизнь без ассертов. Конкретно в данном случае это всего лишь пример, там можете строить что хотите сами. Но если бы конкретно мне понадобилась такая конструкция, то я бы сгенерировал исключение каким-то образом, а потом разбирался уже исключительно по PC (например, напечатав его в обработчике исключения). Немногим труднее, чем имя функции и номер строки, но зато куда меньше попутных приколов, например, совершенно не нужной в обычной жизни работе со стеком.
  17. Конкретно в данном случае - без использования CMSIS. Теперь о рукопашности этого ассерта и вообще кривости конкретно данного кода. Правильно писать вот так, если не отключать ассерты: if (portNum>=8) return LPC_GPIO_PORT->PIN[portNum]; else Abort(); Потому что ветка true - это более частая ветка, скорее всего с вероятностью 100%.
  18. Я не об этом. А о том, что куча таких же кривых проверок и насилия над стеком есть и в других процедурах библиотеки. Или у Вас только GPIO через библиотеку, а упомянутая остальная периферия - вся аккуратненько врукопашную?
  19. Там же небось такой рукопашный assert один на всех. И прекрасно живет и во всех остальных библиотечных процедурах, в том числе и тех, которые
  20. На каждое чтение порта вот такое вот? Зачем тогда сама тема про анализ листингов? Смысл их анализировать, если быстродействие релиза реально проваливается просто отказом от удаления отладочных пирогов? И да, неужели настолько сложно написать работу с портами с предсказуемыми последствиями?
  21. Тут главное не забыть в релизе сделать так: #define CHECK_PARAM(expr) Чтобы функция приняла вменяемый вид без насилия над стеком: \ In section .text, align 2, keep-with-next 137 uint32_t GPIO_ReadValue( uint8_t portNum ) 138 { 139 CHECK_PARAM(portNum < 8); 140 return LPC_GPIO_PORT->PIN[portNum]; \ GPIO_ReadValue: (+1) \ 0x0 0x.... LDR.N R1,??DataTable4 ;; 0x400f6100 \ 0x2 0xF851 0x0020 LDR R0,[R1, R0, LSL #+2] \ 0x6 0x4770 BX LR ;; return Ну и, к сожалению, inline - это вообще редкая птица во всяких этих библиотеках для не умеющих прочитать содержимое порта сразу по месту в собственном коде.
  22. Ну все-таки не совсем. Если бы я делал asm("UQSUB16 %0,%0,%1":"+r"(max):"r"(*_s++)); - вот тогда да, ассемблер. А так пока никакого выхода за границу разумного для чистого ЯВУшника - ну подумаешь, есть функция __uqsub16(), которая хитро вычитает половинки long'ов. Приведу пример с большого брата (да, Intel'у отдельный котел в аду черти растопили за то, что в SIMD-инструкциях нет знакового сложения с сатурацией для пачки 32хбитных операндов, приходится вот такое изобретать): static inline __m128i selectb(__m128i s, __m128i a, __m128i b) { #if 1 // SSE4.1 supported return _mm_blendv_epi8(b, a, s); #else return _mm_or_si128( _mm_and_si128(s, a), _mm_andnot_si128(s, b)); #endif } static inline __m128i add_saturated(__m128i a, __m128i b) { __m128i sum = _mm_add_epi32(a, b); // a + b __m128i axb = _mm_xor_si128(a, b); // check if a and b have different sign __m128i axs = _mm_xor_si128(a, sum); // check if a and sum have different sign __m128i overf1 = _mm_andnot_si128(axb, axs); // check if sum has wrong sign __m128i overf2 = _mm_srai_epi32(overf1, 31); // -1 if overflow __m128i asign = _mm_srli_epi32(a, 31); // 1 if a < 0 __m128i sat1 = _mm_srli_epi32(overf2, 1); // 7FFFFFFF if overflow __m128i sat2 = _mm_add_epi32(sat1, asign); // 7FFFFFFF if positive overflow 80000000 if negative overflow return selectb(overf2, sat2, sum); // sum if not overflow, else sat2 } Это asm или не asm?
  23. Если нельзя, но очень хочется - то можно: #define PROCESS2(V) max=__UQSUB16(max,V)+V; unsigned long findmaxv2(unsigned short *_s) { unsigned long max=0; unsigned long a0,a1,a2,a3,a4,a5,a6,a7; for(unsigned long i=0; i<512/(2*8); i++) { asm("LDMIA %0!,{%1,%2,%3,%4,%5,%6,%7,%8}": "+r"(_s), "=r"(a0),"=r"(a1),"=r"(a2),"=r"(a3), "=r"(a4),"=r"(a5),"=r"(a6),"=r"(a7)); PROCESS2(a0); PROCESS2(a1); PROCESS2(a2); PROCESS2(a3); PROCESS2(a4); PROCESS2(a5); PROCESS2(a6); PROCESS2(a7); } if ((max>>16)>(max&0xFFFF)) return max>>16; return max&0xFFFF; } Конечно, в реальной жизни надо подавить warning, который понятно почему возникает. И цикл минимально развернуть. Понятное дело, без знания asm'а такое не напишешь, но по сравнению с чистым asm'ом - не надо самому корячиться с прологами/эпилогами и всей остальной сопутствующей шляпой.
  24. Ну допустим так: #include <intrinsics.h> #define PROCESS4() acc=*s++; max=__UQSUB16(max,acc)+acc; max=__UQSUB16(max,acc>>32)+(acc>>32) unsigned long findmax(unsigned short *_s) { unsigned long max=0; unsigned long long acc; unsigned long long *s=(unsigned long long *)_s; for(unsigned long i=0; i<512/(4*4); i++) { PROCESS4(); PROCESS4(); PROCESS4(); PROCESS4(); } if ((max>>16)>(max&0xFFFF)) return max>>16; return max&0xFFFF; } Понятное дело, что развернуть можно чуть больше, если сильно надо. Основной провал по сравнению с asm-вариантом - невозможность загрузить сразу кучу переменных при помощи LDM, потому LDRD в качестве оптимизации. Но это IAR такой, насколько я знаю, GCC вроде бы умеет. А так, конечно, да, по сравнению с тем, что может накалякать какой-нибудь залетный формошлеп - это магия ;)