-
Постов
4 619 -
Зарегистрирован
-
Победитель дней
2
Сообщения, опубликованные Rst7
-
-
Кстати, это только к Cortex-M относится, всякие -А вроде не сбрасывают.
-
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)
QuoteThe 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.
Т.к. прерывания - это тоже эксепшн, то вот и ответ.
-
4 minutes ago, esaulenka said:
Объясните, пожалуйста.
Например непонимание работы exclusive monitor'а ядра тут:
QuoteЕсли между LDREX и STREX произошло прерывание и оно что-то записало в память (а оно обязательно хоть регистры, да сохранит в стек), то STREX ничего не запишет в память и в выходной регистре будет записана 1.
-
Какие-то очень сложные у вас всех TFTP. У меня от LPC1768 загрузчик весит
Quote6 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, который можно выбросить, если сильно прижмет.
Кстати, я его где-то выкладывал тут.
-
1 hour ago, AlexandrY said:
RT1020 устарел не родившись.
Теперь все только и говорят о Cortex-M55 совместно с Ethos-U55.
Готовтесь перепиливать свой RNDIS под новую архитектуру.*facepalm.jpg*
-
32 minutes ago, mantech said:
Это почти везде так, начиная еще с MQXа когда все вроде работает,
Там все хуже, там просто не работает. Виснет намертво сразу.
-
6 hours ago, haker_fox said:
Но уважаемый @lamerok вообще-то является членом нашего клуба с давних времён. И как-то некрасиво говорить в адрес своего коллеги такие вещи.
Очень жаль, что участник нашего форума оказался таким провальным. Если бы он это все высказывал тут в дискуссиях - то пофиг. А вот то, что он это несет в неокрепшие умы (я же не просто так цитату принес) - вот за это нет прощения.
-
26 minutes ago, AlexandrY said:
В i.MX RT USB стеке всего 66 файлов объемом 1,87 Мегабайт.
Давайте, кстати, проверим на вшивость Ваш прекрасный дорогой софт.
Что у Вас в заголовочнике с регистрами от RT1020 описано для USB_USBCMD_ATDTW_MASK и USB_USBCMD_ATDTW_SHIFT?
-
3 minutes ago, AlexandrY said:
Вы просто купились на халявный, но откровенно слабый софт.
А причем тут "слабый софт"?
6 minutes ago, AlexandrY said:Одно дело трудность освоения чужого кода, и совсем другое поддержка своего middleware. Последнее не оправдывается по нынешним временам.
Это зачем мне чужой код осваивать? Я за свое могу нести ответственность, а за чужое - пардон. Чтобы за чужое нести ответственность - надо его досконально изучить, а это сравнимо с написанием своего.
-
25 minutes ago, one_eight_seven said:
Что-то хорошее там есть? Просто за первые две минуты у меня пошла кровь из глаз, и я больше не хочу иметь зрение.
Там еще и дичь про LDREX/STREX написана. Я бы вообще дал этому дьяволу по лицу. Именно за вот это:
QuoteКак я уже говорил, я обучаю студентов разработке ПО для измерительных устройств. Работа в университете — это мое хобби, основное место работы с университетом не связано, но тоже коррелирует с разработкой встроенного софта, в том числе и для высоко-надежных систем.
-
Вот прям могу с пылу с жару рассказать про борьбу с 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 у меня - один сишный файл вполне обозримых размеров. С минимумом оверхэда, как я люблю.
-
16 minutes ago, haker_fox said:
Кстати, а как вы делаете Abort(). Не используете SVC и MPU?
Я - никак не делаю, живу жизнь без ассертов. Конкретно в данном случае это всего лишь пример, там можете строить что хотите сами. Но если бы конкретно мне понадобилась такая конструкция, то я бы сгенерировал исключение каким-то образом, а потом разбирался уже исключительно по PC (например, напечатав его в обработчике исключения). Немногим труднее, чем имя функции и номер строки, но зато куда меньше попутных приколов, например, совершенно не нужной в обычной жизни работе со стеком.
-
5 minutes ago, haker_fox said:
Кстати, а что вы под этим подразумеваете? Стиль кодирования?
Конкретно в данном случае - без использования CMSIS.
Теперь о рукопашности этого ассерта и вообще кривости конкретно данного кода.
Правильно писать вот так, если не отключать ассерты:
if (portNum>=8) return LPC_GPIO_PORT->PIN[portNum]; else Abort();
Потому что ветка true - это более частая ветка, скорее всего с вероятностью 100%.
-
Just now, haker_fox said:
Добавляется запись в аварийный журнал в энергонезависимую память.
Я не об этом. А о том, что куча таких же кривых проверок и насилия над стеком есть и в других процедурах библиотеки. Или у Вас только GPIO через библиотеку, а упомянутая остальная периферия - вся аккуратненько врукопашную?
-
1 minute ago, haker_fox said:
В железяке, для которой программа, работы с GPIO очень мало, и она проводится один раз по-сути, при настройке системы.
Там же небось такой рукопашный assert один на всех. И прекрасно живет и во всех остальных библиотечных процедурах, в том числе и тех, которые
5 minutes ago, haker_fox said:Далее работают DMA, SSP, SGPIO (LPC4337) и прочая периферия.
-
26 minutes ago, haker_fox said:
Я в релизе оставляю. Ибо пусть лучше сработает такая ловушка с последующим логированием, чем причина непонятной работы прибора останется тайной.
На каждое чтение порта вот такое вот? Зачем тогда сама тема про анализ листингов? Смысл их анализировать, если быстродействие релиза реально проваливается просто отказом от удаления отладочных пирогов?
И да, неужели настолько сложно написать работу с портами с предсказуемыми последствиями?
-
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 - это вообще редкая птица во всяких этих библиотеках для не умеющих прочитать содержимое порта сразу по месту в собственном коде.
-
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?
-
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; }
Spoiler80 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'ом - не надо самому корячиться с прологами/эпилогами и всей остальной сопутствующей шляпой.
-
Ну допустим так:
#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; }
Spoiler62 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 вроде бы умеет.
А так, конечно, да, по сравнению с тем, что может накалякать какой-нибудь залетный формошлеп - это магия ;)
-
49 minutes ago, jcxz said:
Ну и получили примерно то же самое, что у меня на выходе генератора полиморфного кода. Только с ветвлением на входе, да состоящее из двух кусков. Т.е. - по скорости не лучше, а скорее несколько хуже.
Зато данные всегда выровнены. Нет штрафа за запись по некруглому адресу. Что скорее всего перекроет расходы на TBB.
57 minutes ago, jcxz said:Особенно касается алгоритма поиска максимума/минимума на массиве из 512 несортированных 16-разрядных чисел.
К сожалению, для IAR'а есть проблема - он принципиально не желает генерить LDM для разгрузки многих переменных. Потому самый оптимальный вариант не получится. А так intrinsic'и вполне решают задачу. Щас продемонстрирую.
-
Ну и пайплайн врукопашную:
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 ....
Кстати, а вот еще момент:
QuoteLDR Rx,[PC,#imm]
might add a cycle because of contention with the fetch unit.Так что загрузка адреса из списка более эффективна.
-
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: ; } }
И все, бинго:
Spoiler23 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 ** нужен.
-
7 minutes ago, xvr said:
Ну хорошо. Обрисовываю основную идею:
Идея, в общем, ничего так (если флеша вагон), но есть нюанс, касающийся именно ARM. Загрузка регистра из произвольной переменной стоит столько же, сколько *(*list++). На самом деле для ARM загрузка переменной в регистр - это *(*(pc+disp)). Потому никакого выигрыша не будет.
Битовые поля, кто ж вас выдумал?
в Программирование
Опубликовано · Пожаловаться
Верно описывает результат только для Cortex-M. Потому что объяснение неверное.
А зачем писать в переменную, к которой Вы организуете эксклюзивный доступ, обычным способом?
Только менее универсальный. Например, взять элемент из списка на ARM выглядит так:
А на x86 с его единственным lock'ом надо извращаться.