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

Rst7

Модератор
  • Постов

    4 619
  • Зарегистрирован

  • Победитель дней

    2

Сообщения, опубликованные Rst7


  1. 2 hours ago, AHTOXA said:

    - верно описывает результат. Хотя причины объясняет неверно :-)

    Верно описывает результат только для Cortex-M. Потому что объяснение неверное.

    3 hours ago, Kabdim said:

    Эээ т.е. если просто записать в тот же адрес STR'ом вся схема сломается?

    А зачем писать в переменную, к которой Вы организуете эксклюзивный доступ, обычным способом?

    2 hours ago, Kabdim said:

    Жесть, насколько же x86 в этом аспекте прямолинейно правильней.

    Только менее универсальный. Например, взять элемент из списка на 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;
    }
    Spoiler
    
        163          LLITEM *AllocBlock(void)
        164          {
       \                     AllocBlock: (+1)
       \        0x0   0x.... 0x....      LDR.W    R2,??DataTable6_1
        165            LLITEM *p;
        166            LLITEM *next;
        167            do
        168            {
        169              p=(LLITEM*)__LDREX(ExAddr(FreeBlocks));
       \                     ??AllocBlock_0: (+1)
       \        0x4   0xE852 0x0F00      LDREX    R0,[R2]
        170              if (!p) {__CLREX(); return p;}
       \        0x8   0xB128             CBZ.N    R0,??AllocBlock_1
        171              next=p->next;
        172            }while(__STREX((unsigned long)next,ExAddr(FreeBlocks)));
       \        0xA   0x6803             LDR      R3,[R0, #+0]
       \        0xC   0xE842 0x3100      STREX    R1,R3,[R2]
       \       0x10   0x2900             CMP      R1,#+0
       \       0x12   0xD1F7             BNE.N    ??AllocBlock_0
        173            return p;
       \       0x14   0x4770             BX       LR               ;; return
       \                     ??AllocBlock_1: (+1)
       \       0x16   0xF3BF 0x8F2F      CLREX    
       \       0x1A   0x4770             BX       LR
        174          }

     

    А на x86 с его единственным lock'ом надо извращаться.

  2. 17 minutes ago, AHTOXA said:

    что прерывания таки сбрасывают флаг экслюзивного доступа, даже если в обработчике ничего не делается.

    Я не об этом. Обычная запись в память (или чтение) между 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)

    Quote

    The processor removes its exclusive access tag if:

    • It executes a CLREX instruction.

    • It executes a Store-Exclusive instruction, regardless of whether the write succeeds.

    • An exception occurs. This means the processor can resolve semaphore conflicts between different threads.

    Т.к. прерывания - это тоже эксепшн, то вот и ответ.

  3. 4 minutes ago, esaulenka said:

    Объясните, пожалуйста.

    Например непонимание работы exclusive monitor'а ядра тут:

    Quote

    Если между LDREX и STREX произошло прерывание и оно что-то записало в память (а оно обязательно хоть регистры, да сохранит в стек), то STREX ничего не запишет в память и в выходной регистре будет записана 1.

     

  4. Какие-то очень сложные у вас всех TFTP. У меня от LPC1768 загрузчик весит

    Quote

      6 614 bytes of readonly  code memory
         20 bytes of readwrite code memory
         74 bytes of readonly  data memory
      4 180 bytes of readwrite data memory (+ 263 absolute)
     

    Из которых 1132 байта - это библиотечный printf, который можно выбросить, если сильно прижмет.

    Кстати, я его где-то выкладывал тут.

  5. 6 hours ago, haker_fox said:

    Но уважаемый @lamerok вообще-то является членом нашего клуба с давних времён. И как-то некрасиво говорить в адрес своего коллеги такие вещи.

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

  6. 26 minutes ago, AlexandrY said:

    В i.MX RT USB стеке всего 66 файлов объемом 1,87 Мегабайт.

    Давайте, кстати, проверим на вшивость Ваш прекрасный дорогой софт.

    Что у Вас в заголовочнике с регистрами от RT1020 описано для USB_USBCMD_ATDTW_MASK и USB_USBCMD_ATDTW_SHIFT?

  7. 3 minutes ago, AlexandrY said:

    Вы просто купились на халявный, но откровенно слабый софт.

    А причем тут "слабый софт"?

    6 minutes ago, AlexandrY said:

    Одно дело трудность освоения чужого кода, и совсем другое поддержка своего middleware. Последнее не оправдывается по нынешним временам. 

    Это зачем мне чужой код осваивать? Я за свое могу нести ответственность, а за чужое - пардон. Чтобы за чужое нести ответственность - надо его досконально изучить, а это сравнимо с написанием своего.

  8. 25 minutes ago, one_eight_seven said:

    Что-то хорошее там есть? Просто за первые две минуты у меня пошла кровь из глаз, и я больше не хочу иметь зрение.

    Там еще и дичь про LDREX/STREX написана. Я бы вообще дал этому дьяволу по лицу. Именно за вот это:

    Quote

    Как я уже говорил, я обучаю студентов разработке ПО для измерительных устройств. Работа в университете — это мое хобби, основное место работы с университетом не связано, но тоже коррелирует с разработкой встроенного софта, в том числе и для высоко-надежных систем.

     

  9. Вот прям могу с пылу с жару рассказать про борьбу с USB-стеком. Камень - iMX RT1020. Имею принцип в жизни - писать самому, готовое не использовать, максимум - подглядеть в примеры какие-то опущенные в даташитах подробности.

     

    Spoiler

    Сразу скажу, что на камень омерзительная документация. Куча умолчаний, куча неочевидных вещей, разбросанных по всей доке, с отсутствием прямых указаний, где поглядеть. И куча банальных недосмотров типа обозначения пунктов в алгоритме буквами a, b, c..., а ссылки в этом алгоритме типа "go to step 5". В свое время приходилось работать с мотороловскими процами во времена 680x0 - тогда у них документация была просто песней. Ну и у NXP тоже всегда была отличная. Я не ожидал, что так будет провально.

     

    Я не особо часто бодался с USB, последний раз лет эдак 15 назад делал эмулятор FT232 на AT90USB162. А теперь пришлось сделать ECM/RNDIS устройство. Официальные примеры для этих iMX RT есть, но со страшным нагромождением уровней абстракции, разбросано по куче файлов, местами - плюсы на Си врукопашную, в общем - все прелести.

    Довольно быстро все поехало в простом варианте типа суперцикла, без всяких прерываний, просто с проверкой флагов. Затем начал переделывать на вменяемую работу, т.е. прерывания, обеспечение zero copy, минимальные простои и так далее. И в конце концов наступил на мертвое зависание алгоритма добавления нового буфера в цепочку буферов USB DMA на ходу. Алгоритм описан в даташите, более того, именно его реализацию (не без индусских делов) я обнаружил при изучении примеров (после того, как моя реализация не заработала). Убито было несколько дней. Оказалось, что в заголовочном файле с регистрами периферии был неверно описан один из битов в регистрах (не 1<<14, а 1<<12). Обнаружил это совершенно случайно, когда уже начал проверять совсем все. Заголовочный файл с регистрами был взят именно из официальных примеров. Так что официальные примеры, конечно, компилируются, но вот никто их на таргете никогда не запускал и не проверял. Вообще оказалось, что во всей этой iMX-линейке вроде бы и один и тот же USB, но этот бит пляшет произвольно от типа к типу, в каких-то - 12й, в каких-то - 14й, в некоторых это считалось ошибкой и описано в errata, в некоторых нет, в общем - полный хаос.

    Это в общем я к тому, что взяв "готовый" можно влететь крепко с точки зрения "я возьму готовый, сэкономлю дофига времени". Ну и да, по итогу весь этот RNDIS у меня - один сишный файл вполне обозримых размеров. С минимумом оверхэда, как я люблю.

  10. 16 minutes ago, haker_fox said:

    Кстати, а как вы делаете Abort(). Не используете SVC и MPU?

    Я - никак не делаю, живу жизнь без ассертов. Конкретно в данном случае это всего лишь пример, там можете строить что хотите сами. Но если бы конкретно мне понадобилась такая конструкция, то я бы сгенерировал исключение каким-то образом, а потом разбирался уже исключительно по PC (например, напечатав его в обработчике исключения). Немногим труднее, чем имя функции и номер строки, но зато куда меньше попутных приколов, например, совершенно не нужной в обычной жизни работе со стеком.

  11. 5 minutes ago, haker_fox said:

    Кстати, а что вы под этим подразумеваете? Стиль кодирования?

    Конкретно в данном случае - без использования CMSIS.

    Теперь о рукопашности этого ассерта и вообще кривости конкретно данного кода.

    Правильно писать вот так, если не отключать ассерты:

      if (portNum>=8)
        return LPC_GPIO_PORT->PIN[portNum];
      else
        Abort();

    Потому что ветка true - это более частая ветка, скорее всего с вероятностью 100%.

  12. Just now, haker_fox said:

    Добавляется запись в аварийный журнал в энергонезависимую память.

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

  13. 1 minute ago, haker_fox said:

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

    Там же небось такой рукопашный assert один на всех. И прекрасно живет и во всех остальных библиотечных процедурах, в том числе и тех, которые

    5 minutes ago, haker_fox said:

    Далее работают DMA, SSP, SGPIO (LPC4337) и прочая периферия.

     

  14. 26 minutes ago, haker_fox said:

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

    На каждое чтение порта вот такое вот? Зачем тогда сама тема про анализ листингов? Смысл их анализировать, если быстродействие релиза реально проваливается просто отказом от удаления отладочных пирогов?

    И да, неужели настолько сложно написать работу с портами с предсказуемыми последствиями?

  15. 3 hours ago, haker_fox said:

    Но в целом компилятор не упрекнёшь) Функция dprintf не будет вызвана.

    Тут главное не забыть в релизе сделать так:

    #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 - это вообще редкая птица во всяких этих библиотеках для не умеющих прочитать содержимое порта сразу по месту в собственном коде.

  16. 7 minutes ago, jcxz said:

    Так ведь они (intrinsic'и) - это уже собственно ассемблер. Завуалированный.

    Ну все-таки не совсем. Если бы я делал 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?

  17. 20 minutes ago, Rst7 said:

    невозможность загрузить сразу кучу переменных при помощи LDM

    Если нельзя, но очень хочется - то можно:

    #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;
    }
    Spoiler
    
         80          unsigned long findmaxv2(unsigned short *_s)
         81          {
       \                     findmaxv2: (+1)
       \        0x0   0xE92D 0x41F0      PUSH     {R4-R8,LR}
       \        0x4   0x4606             MOV      R6,R0
         82            unsigned long max=0;
       \        0x6   0x2700             MOVS     R7,#+0
         83            unsigned long a0,a1,a2,a3,a4,a5,a6,a7;
         84            for(unsigned long i=0; i<512/(2*8); i++)
       \        0x8   0xF05F 0x0520      MOVS.W   R5,#+32
         85            {
         86              asm("LDMIA %0!,{%1,%2,%3,%4,%5,%6,%7,%8}":
                                                                ^
    Warning[Og014]: Warning in inline assembly: "Registers are not specified in
              ascending order"
         87                    "+r"(_s),
         88                    "=r"(a0),"=r"(a1),"=r"(a2),"=r"(a3),
         89                    "=r"(a4),"=r"(a5),"=r"(a6),"=r"(a7));
       \                     ??findmaxv2_0: (+1)
       \        0xC   0xE8B6 0x511F      LDMIA R6!,{R8,LR,R12,R0,R1,R2,R3,R4}
         90              PROCESS2(a0);
         91              PROCESS2(a1);
         92              PROCESS2(a2);
         93              PROCESS2(a3);
         94              PROCESS2(a4);
         95              PROCESS2(a5);
         96              PROCESS2(a6);
         97              PROCESS2(a7);
       \       0x10   0xFAD7 0xF758      UQSUB16  R7,R7,R8
       \       0x14   0x44B8             ADD      R8,R8,R7
       \       0x16   0xFAD8 0xF75E      UQSUB16  R7,R8,LR
       \       0x1A   0x44BE             ADD      LR,LR,R7
       \       0x1C   0xFADE 0xF75C      UQSUB16  R7,LR,R12
       \       0x20   0x44BC             ADD      R12,R12,R7
       \       0x22   0xFADC 0xF750      UQSUB16  R7,R12,R0
       \       0x26   0x19C0             ADDS     R0,R0,R7
       \       0x28   0xFAD0 0xF051      UQSUB16  R0,R0,R1
       \       0x2C   0x1809             ADDS     R1,R1,R0
       \       0x2E   0xFAD1 0xF052      UQSUB16  R0,R1,R2
       \       0x32   0x1812             ADDS     R2,R2,R0
       \       0x34   0xFAD2 0xF053      UQSUB16  R0,R2,R3
       \       0x38   0x181B             ADDS     R3,R3,R0
       \       0x3A   0xFAD3 0xF754      UQSUB16  R7,R3,R4
       \       0x3E   0x19E7             ADDS     R7,R4,R7
         98            }
       \       0x40   0x1E6D             SUBS     R5,R5,#+1
       \       0x42   0xD1E3             BNE.N    ??findmaxv2_0
         99            if ((max>>16)>(max&0xFFFF)) return max>>16;
       \       0x44   0x0C38             LSRS     R0,R7,#+16
       \       0x46   0xB2BF             UXTH     R7,R7
       \       0x48   0x4287             CMP      R7,R0
       \       0x4A   0xBF28             IT       CS 
       \       0x4C   0x4638             MOVCS    R0,R7
        100            return max&0xFFFF;
       \       0x4E   0xE8BD 0x81F0      POP      {R4-R8,PC}       ;; return
        101          }
    

     

    Конечно, в реальной жизни надо подавить warning, который понятно почему возникает. И цикл минимально развернуть.

    Понятное дело, без знания asm'а такое не напишешь, но по сравнению с чистым asm'ом - не надо самому корячиться с прологами/эпилогами и всей остальной сопутствующей шляпой.

  18. Ну допустим так:

    #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;
    }
    Spoiler

         62          unsigned long findmax(unsigned short *_s)
    		     63          {
    		   \                     findmax: (+1)
    		   \        0x0   0xB470             PUSH     {R4-R6}
    		     64            unsigned long max=0;
    		     65            unsigned long long acc;
    		     66            unsigned long long *s=(unsigned long long *)_s;
    		     67            for(unsigned long i=0; i<512/(4*4); i++)
    		   \        0x2   0x4601             MOV      R1,R0
    		   \        0x4   0x2600             MOVS     R6,#+0
    		   \        0x6   0x2020             MOVS     R0,#+32
    		     68            {
    		     69              PROCESS4();
    		   \                     ??findmax_0: (+1)
    		   \        0x8   0xE8F1 0x2302      LDRD     R2,R3,[R1], #+8
    		   \        0xC   0xFAD6 0xF652      UQSUB16  R6,R6,R2
    		   \       0x10   0x1996             ADDS     R6,R2,R6
    		     70              PROCESS4();
    		   \       0x12   0xE8F1 0x4502      LDRD     R4,R5,[R1], #+8
    		   \       0x16   0xFAD6 0xF253      UQSUB16  R2,R6,R3
    		   \       0x1A   0x18D2             ADDS     R2,R2,R3
    		   \       0x1C   0xFAD2 0xF254      UQSUB16  R2,R2,R4
    		   \       0x20   0x18A2             ADDS     R2,R4,R2
    		   \       0x22   0xFAD2 0xF255      UQSUB16  R2,R2,R5
    		   \       0x26   0x1952             ADDS     R2,R2,R5
    		     71              PROCESS4();
    		   \       0x28   0xE8F1 0x4502      LDRD     R4,R5,[R1], #+8
    		   \       0x2C   0xFAD2 0xF254      UQSUB16  R2,R2,R4
    		   \       0x30   0x18A2             ADDS     R2,R4,R2
    		   \       0x32   0xFAD2 0xF255      UQSUB16  R2,R2,R5
    		   \       0x36   0x1952             ADDS     R2,R2,R5
    		     72              PROCESS4();
    		   \       0x38   0xE8F1 0x4502      LDRD     R4,R5,[R1], #+8
    		   \       0x3C   0xFAD2 0xF254      UQSUB16  R2,R2,R4
    		   \       0x40   0x18A2             ADDS     R2,R4,R2
    		   \       0x42   0xFAD2 0xF255      UQSUB16  R2,R2,R5
    		   \       0x46   0x1956             ADDS     R6,R2,R5
    		     73            }
    		   \       0x48   0x1E40             SUBS     R0,R0,#+1
    		   \       0x4A   0xD1DD             BNE.N    ??findmax_0
    		     74            if ((max>>16)>(max&0xFFFF)) return max>>16;
    		   \       0x4C   0x0C30             LSRS     R0,R6,#+16
    		   \       0x4E   0xB2B6             UXTH     R6,R6
    		   \       0x50   0x4286             CMP      R6,R0
    		   \       0x52   0xBF28             IT       CS 
    		   \       0x54   0x4630             MOVCS    R0,R6
    		     75            return max&0xFFFF;
    		   \       0x56   0xBC70             POP      {R4-R6}
    		   \       0x58   0x4770             BX       LR               ;; return
    		     76          }

    Понятное дело, что развернуть можно чуть больше, если сильно надо. Основной провал по сравнению с asm-вариантом - невозможность загрузить сразу кучу переменных при помощи LDM, потому LDRD в качестве оптимизации. Но это IAR такой, насколько я знаю, GCC вроде бы умеет.

     

    А так, конечно, да, по сравнению с тем, что может накалякать какой-нибудь залетный формошлеп - это магия ;)

  19. 49 minutes ago, jcxz said:

    Ну и получили примерно то же самое, что у меня на выходе генератора полиморфного кода. Только с ветвлением на входе, да состоящее из двух кусков. Т.е. - по скорости не лучше, а скорее несколько хуже.

    Зато данные всегда выровнены. Нет штрафа за запись по некруглому адресу. Что скорее всего перекроет расходы на TBB.

    57 minutes ago, jcxz said:

    Особенно касается алгоритма поиска максимума/минимума на массиве из 512 несортированных 16-разрядных чисел.

    К сожалению, для IAR'а есть проблема - он принципиально не желает генерить LDM для разгрузки многих переменных. Потому самый оптимальный вариант не получится. А так intrinsic'и вполне решают задачу. Щас продемонстрирую.

  20. Ну и пайплайн врукопашную:

    	void DumpDuff(long *d, long **s, int len32)
    {
      long *p=*s++;
      long v;
      switch(len32)
      {
      default:
      case 28: v=*p; p=*s++; *d++=v;
      case 27: v=*p; p=*s++; *d++=v;
      case 26: v=*p; p=*s++; *d++=v;
      case 25: v=*p; p=*s++; *d++=v;
      case 24: v=*p; p=*s++; *d++=v;
    ....
    	

    	     29            default:
         30            case 28: v=*p; p=*s++; *d++=v;
       \                     ??DumpDuff_1: (+1)
       \       0x2A   0x681A             LDR      R2,[R3, #+0]
       \       0x2C   0xF851 0x3B04      LDR      R3,[R1], #+4
       \       0x30   0xF840 0x2B04      STR      R2,[R0], #+4
         31            case 27: v=*p; p=*s++; *d++=v;
       \                     ??DumpDuff_2: (+1)
       \       0x34   0x681A             LDR      R2,[R3, #+0]
       \       0x36   0xF851 0x3B04      LDR      R3,[R1], #+4
       \       0x3A   0xF840 0x2B04      STR      R2,[R0], #+4
         32            case 26: v=*p; p=*s++; *d++=v;
       \                     ??DumpDuff_3: (+1)
       \       0x3E   0x681A             LDR      R2,[R3, #+0]
       \       0x40   0xF851 0x3B04      LDR      R3,[R1], #+4
       \       0x44   0xF840 0x2B04      STR      R2,[R0], #+4
    ....
    	

    Кстати, а вот еще момент:

    Quote

    LDR Rx,[PC,#imm] might add a cycle because of contention with the fetch unit.

    Так что загрузка адреса из списка более эффективна.

  21. 34 minutes ago, xvr said:

    Уберётся инкремент указателя на каждую загрузку

    Это в ARM бесплатно.

    20 minutes ago, jcxz said:

    Во-вторых: Как раз "разворотов цикла" по логике работы алгоритма быть не должно. Какие могут быть развороты если входные данные - переменные? Вы просто неправильно задали условия компиляции.

    Все я правильно задал. Циклы разворачиваются не на константное число. А все что можно, делается блоками по несколько итераций, а остальное - уже по одной штучке. На самом деле, если у Вас действительно ограничено число переменных, то Duff Device - это самое то в данном случае.

     

    22 minutes ago, jcxz said:

    А у меня максимальное количество одновременно включённых каналов осциллографирования от 14 до 28.

    Ага, ну тогда - DD:

    	void DumpDuff(long *d, long **s, int len32)
    {
      switch(len32)
      {
      default:
      case 28: *d++=*(*s++);
      case 27: *d++=*(*s++);
      case 26: *d++=*(*s++);
      case 25: *d++=*(*s++);
      case 24: *d++=*(*s++);
      case 23: *d++=*(*s++);
      case 22: *d++=*(*s++);
      case 21: *d++=*(*s++);
      case 20: *d++=*(*s++);
      case 19: *d++=*(*s++);
      case 18: *d++=*(*s++);
      case 17: *d++=*(*s++);
      case 16: *d++=*(*s++);
      case 15: *d++=*(*s++);
      case 14: *d++=*(*s++);
      case 13: *d++=*(*s++);
      case 12: *d++=*(*s++);
      case 11: *d++=*(*s++);
      case 10: *d++=*(*s++);
      case 9: *d++=*(*s++);
      case 8: *d++=*(*s++);
      case 7: *d++=*(*s++);
      case 6: *d++=*(*s++);
      case 5: *d++=*(*s++);
      case 4: *d++=*(*s++);
      case 3: *d++=*(*s++);
      case 2: *d++=*(*s++);
      case 1: *d++=*(*s++);
      case 0: ;
      }
    }
    	

    И все, бинго:

    Spoiler

    				
    			     23          void DumpDuff(long *d, long **s, int len32)
    		     24          {
    		   \                     DumpDuff: (+1)
    		   \        0x0   0xB410             PUSH     {R4}
    		     25            switch(len32)
    		   \        0x2   0x2A1B             CMP      R2,#+27
    		   \        0x4   0xD80F             BHI.N    ??DumpDuff_1
    		   \        0x6   0xE8DF 0xF002      TBB      [PC, R2]
    		   \                     ??DumpDuff_0:
    		   \        0xA   0x98 0x95          DC8      0x98,0x95,0x90,0x8B
    		   \              0x90 0x8B    
    		   \        0xE   0x86 0x81          DC8      0x86,0x81,0x7C,0x77
    		   \              0x7C 0x77    
    		   \       0x12   0x72 0x6D          DC8      0x72,0x6D,0x68,0x63
    		   \              0x68 0x63    
    		   \       0x16   0x5E 0x59          DC8      0x5E,0x59,0x54,0x4F
    		   \              0x54 0x4F    
    		   \       0x1A   0x4A 0x45          DC8      0x4A,0x45,0x40,0x3B
    		   \              0x40 0x3B    
    		   \       0x1E   0x36 0x31          DC8      0x36,0x31,0x2C,0x27
    		   \              0x2C 0x27    
    		   \       0x22   0x22 0x1D          DC8      0x22,0x1D,0x18,0x13
    		   \              0x18 0x13    
    		     26            {
    		     27            default:
    		     28            case 28: *d++=*(*s++);
    		   \                     ??DumpDuff_1: (+1)
    		   \       0x26   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0x2A   0x6813             LDR      R3,[R2, #+0]
    		   \       0x2C   0xF840 0x3B04      STR      R3,[R0], #+4
    		     29            case 27: *d++=*(*s++);
    		   \                     ??DumpDuff_2: (+1)
    		   \       0x30   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \       0x34   0x6822             LDR      R2,[R4, #+0]
    		   \       0x36   0xF840 0x2B04      STR      R2,[R0], #+4
    		     30            case 26: *d++=*(*s++);
    		   \                     ??DumpDuff_3: (+1)
    		   \       0x3A   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \       0x3E   0x681C             LDR      R4,[R3, #+0]
    		   \       0x40   0xF840 0x4B04      STR      R4,[R0], #+4
    		     31            case 25: *d++=*(*s++);
    		   \                     ??DumpDuff_4: (+1)
    		   \       0x44   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0x48   0x6813             LDR      R3,[R2, #+0]
    		   \       0x4A   0xF840 0x3B04      STR      R3,[R0], #+4
    		     32            case 24: *d++=*(*s++);
    		   \                     ??DumpDuff_5: (+1)
    		   \       0x4E   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \       0x52   0x6822             LDR      R2,[R4, #+0]
    		   \       0x54   0xF840 0x2B04      STR      R2,[R0], #+4
    		     33            case 23: *d++=*(*s++);
    		   \                     ??DumpDuff_6: (+1)
    		   \       0x58   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \       0x5C   0x681C             LDR      R4,[R3, #+0]
    		   \       0x5E   0xF840 0x4B04      STR      R4,[R0], #+4
    		     34            case 22: *d++=*(*s++);
    		   \                     ??DumpDuff_7: (+1)
    		   \       0x62   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0x66   0x6813             LDR      R3,[R2, #+0]
    		   \       0x68   0xF840 0x3B04      STR      R3,[R0], #+4
    		     35            case 21: *d++=*(*s++);
    		   \                     ??DumpDuff_8: (+1)
    		   \       0x6C   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \       0x70   0x6822             LDR      R2,[R4, #+0]
    		   \       0x72   0xF840 0x2B04      STR      R2,[R0], #+4
    		     36            case 20: *d++=*(*s++);
    		   \                     ??DumpDuff_9: (+1)
    		   \       0x76   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \       0x7A   0x681C             LDR      R4,[R3, #+0]
    		   \       0x7C   0xF840 0x4B04      STR      R4,[R0], #+4
    		     37            case 19: *d++=*(*s++);
    		   \                     ??DumpDuff_10: (+1)
    		   \       0x80   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0x84   0x6813             LDR      R3,[R2, #+0]
    		   \       0x86   0xF840 0x3B04      STR      R3,[R0], #+4
    		     38            case 18: *d++=*(*s++);
    		   \                     ??DumpDuff_11: (+1)
    		   \       0x8A   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \       0x8E   0x6822             LDR      R2,[R4, #+0]
    		   \       0x90   0xF840 0x2B04      STR      R2,[R0], #+4
    		     39            case 17: *d++=*(*s++);
    		   \                     ??DumpDuff_12: (+1)
    		   \       0x94   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \       0x98   0x681C             LDR      R4,[R3, #+0]
    		   \       0x9A   0xF840 0x4B04      STR      R4,[R0], #+4
    		     40            case 16: *d++=*(*s++);
    		   \                     ??DumpDuff_13: (+1)
    		   \       0x9E   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0xA2   0x6813             LDR      R3,[R2, #+0]
    		   \       0xA4   0xF840 0x3B04      STR      R3,[R0], #+4
    		     41            case 15: *d++=*(*s++);
    		   \                     ??DumpDuff_14: (+1)
    		   \       0xA8   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \       0xAC   0x6822             LDR      R2,[R4, #+0]
    		   \       0xAE   0xF840 0x2B04      STR      R2,[R0], #+4
    		     42            case 14: *d++=*(*s++);
    		   \                     ??DumpDuff_15: (+1)
    		   \       0xB2   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \       0xB6   0x681C             LDR      R4,[R3, #+0]
    		   \       0xB8   0xF840 0x4B04      STR      R4,[R0], #+4
    		     43            case 13: *d++=*(*s++);
    		   \                     ??DumpDuff_16: (+1)
    		   \       0xBC   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0xC0   0x6813             LDR      R3,[R2, #+0]
    		   \       0xC2   0xF840 0x3B04      STR      R3,[R0], #+4
    		     44            case 12: *d++=*(*s++);
    		   \                     ??DumpDuff_17: (+1)
    		   \       0xC6   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \       0xCA   0x6822             LDR      R2,[R4, #+0]
    		   \       0xCC   0xF840 0x2B04      STR      R2,[R0], #+4
    		     45            case 11: *d++=*(*s++);
    		   \                     ??DumpDuff_18: (+1)
    		   \       0xD0   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \       0xD4   0x681C             LDR      R4,[R3, #+0]
    		   \       0xD6   0xF840 0x4B04      STR      R4,[R0], #+4
    		     46            case 10: *d++=*(*s++);
    		   \                     ??DumpDuff_19: (+1)
    		   \       0xDA   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0xDE   0x6813             LDR      R3,[R2, #+0]
    		   \       0xE0   0xF840 0x3B04      STR      R3,[R0], #+4
    		     47            case 9: *d++=*(*s++);
    		   \                     ??DumpDuff_20: (+1)
    		   \       0xE4   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \       0xE8   0x6822             LDR      R2,[R4, #+0]
    		   \       0xEA   0xF840 0x2B04      STR      R2,[R0], #+4
    		     48            case 8: *d++=*(*s++);
    		   \                     ??DumpDuff_21: (+1)
    		   \       0xEE   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \       0xF2   0x681C             LDR      R4,[R3, #+0]
    		   \       0xF4   0xF840 0x4B04      STR      R4,[R0], #+4
    		     49            case 7: *d++=*(*s++);
    		   \                     ??DumpDuff_22: (+1)
    		   \       0xF8   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \       0xFC   0x6813             LDR      R3,[R2, #+0]
    		   \       0xFE   0xF840 0x3B04      STR      R3,[R0], #+4
    		     50            case 6: *d++=*(*s++);
    		   \                     ??DumpDuff_23: (+1)
    		   \      0x102   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \      0x106   0x6822             LDR      R2,[R4, #+0]
    		   \      0x108   0xF840 0x2B04      STR      R2,[R0], #+4
    		     51            case 5: *d++=*(*s++);
    		   \                     ??DumpDuff_24: (+1)
    		   \      0x10C   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \      0x110   0x681C             LDR      R4,[R3, #+0]
    		   \      0x112   0xF840 0x4B04      STR      R4,[R0], #+4
    		     52            case 4: *d++=*(*s++);
    		   \                     ??DumpDuff_25: (+1)
    		   \      0x116   0xF851 0x2B04      LDR      R2,[R1], #+4
    		   \      0x11A   0x6813             LDR      R3,[R2, #+0]
    		   \      0x11C   0xF840 0x3B04      STR      R3,[R0], #+4
    		     53            case 3: *d++=*(*s++);
    		   \                     ??DumpDuff_26: (+1)
    		   \      0x120   0xF851 0x4B04      LDR      R4,[R1], #+4
    		   \      0x124   0x6822             LDR      R2,[R4, #+0]
    		   \      0x126   0xF840 0x2B04      STR      R2,[R0], #+4
    		     54            case 2: *d++=*(*s++);
    		   \                     ??DumpDuff_27: (+1)
    		   \      0x12A   0xF851 0x3B04      LDR      R3,[R1], #+4
    		   \      0x12E   0x681C             LDR      R4,[R3, #+0]
    		   \      0x130   0xF840 0x4B04      STR      R4,[R0], #+4
    		     55            case 1: *d++=*(*s++);
    		   \                     ??DumpDuff_28: (+1)
    		   \      0x134   0x6809             LDR      R1,[R1, #+0]
    		   \      0x136   0x680A             LDR      R2,[R1, #+0]
    		   \      0x138   0x6002             STR      R2,[R0, #+0]
    		     56            case 0: ;
    		     57            }
    		     58          }
    		   \                     ??DumpDuff_29: (+1)
    		   \      0x13A   0xBC10             POP      {R4}
    		   \      0x13C   0x4770             BX       LR               ;; return
    		     59          
    		 				
    			

    Аналогично допиливается вторая итерация с short'ами.

    И да, возможно, что для short'ов будет веселее вот так:

    	void DumpDuff16(long *d, short **s, int len32)
    {
      unsigned long v=0;
      switch(len32)
      {
      default:
      case 28: v=*(*s++);
      case 27: *d++=(v<<16)|*(*s++);
      case 26: v=*(*s++);
      case 25: *d++=(v<<16)|*(*s++);
    	....
    	

    	     64            {
         65            default:
         66            case 28: v=*(*s++);
       \                     ??DumpDuff16_1: (+1)
       \       0x28   0xF851 0x2B04      LDR      R2,[R1], #+4
       \       0x2C   0x5ED3             LDRSH    R3,[R2, R3]
         67            case 27: *d++=(v<<16)|*(*s++);
       \                     ??DumpDuff16_2: (+1)
       \       0x2E   0xF851 0x2B04      LDR      R2,[R1], #+4
       \       0x32   0xF9B2 0x4000      LDRSH    R4,[R2, #+0]
       \       0x36   0xEA44 0x4403      ORR      R4,R4,R3, LSL #+16
       \       0x3A   0xF840 0x4B04      STR      R4,[R0], #+4
         68            case 26: v=*(*s++);
       \                     ??DumpDuff16_3: (+1)
       \       0x3E   0xF851 0x3B04      LDR      R3,[R1], #+4
       \       0x42   0xF9B3 0x3000      LDRSH    R3,[R3, #+0]
         69            case 25: *d++=(v<<16)|*(*s++);
       \                     ??DumpDuff16_4: (+1)
       \       0x46   0xF851 0x2B04      LDR      R2,[R1], #+4
       \       0x4A   0xF9B2 0x4000      LDRSH    R4,[R2, #+0]
       \       0x4E   0xEA44 0x4403      ORR      R4,R4,R3, LSL #+16
       \       0x52   0xF840 0x4B04      STR      R4,[R0], #+4
    ....
    	

    Пардон, там, конечно, unsigned short ** нужен.

  22. 7 minutes ago, xvr said:

    Ну хорошо. Обрисовываю основную идею:

    Идея, в общем, ничего так (если флеша вагон), но есть нюанс, касающийся именно ARM. Загрузка регистра из произвольной переменной стоит столько же, сколько *(*list++). На самом деле для ARM загрузка переменной в регистр - это *(*(pc+disp)). Потому никакого выигрыша не будет.

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