-
Постов
4 619 -
Зарегистрирован
-
Победитель дней
2
Сообщения, опубликованные Rst7
-
-
1 minute ago, jcxz said:
Вы же пользуетесь эмулятором для отладки? А зачем? Почему не подняться выше и не "посмотреть на алгоритм работы целиком"? И сразу аналитически найти все проблемы?
Вы не поверите )))) Только отладочная печать и отладочное махание ножками. Математику отлаживаю на большом брате. Так что ни эмуляторы, ни железные отладчики я не использую.
6 minutes ago, jcxz said:Тут дело в том, что некоторые радикально настроенные товарищи уверяют что знание ассемблера вообще не нужно. Вот с этим и не соглашаюсь.
Ну для формошлепов и любителей "нагуглить готовое решение" - не нужно.
-
4 minutes ago, jcxz said:
Нужно было сделать осциллографирование (в реальном времени) содержимого некоторых переменных в ПО.
Дайте я догадаюсь ;) Это же надо было исключительно на этапе отладки? Неужели настолько там все друг с другом запутано, что не получилось отладить по-модульно, например, а не собирать переменные из кучи мест?
5 minutes ago, jcxz said:Я Вам уже приводил пример - Вы так ничего и не ответили по существу: Например - данные поступают от АЦП. И как заставить АЦП присылать уже отсортированные данные, расскажите?
В таком ключе на Ваш вопрос нет ответа. Надо подняться с уровня гайки М3 (поступающих данных от АЦП) и посмотреть на алгоритм работы целиком.
Думаю, что все эти примеры показывают только одно - достаточно поверхностное отношение к системному проектированию.
И главное, Вы не думайте, что я тут пропагандирую "никакого низкого уровня". Я сам большой любитель, например:
Spoiler#pragma inline=forced static long long MULLS(REG32 a, REG32 b) { long long r; asm("SMULL %L0,%H0,%1,%2":"=Rp"(r):"r"(a),"r"(b)); return r; } //#define LL2FRACT_ROUND(VAR) (((VAR)&(1UL<<(FRACT_SHIFT-1))?(VAR)>>FRACT_SHIFT:((VAR)>>FRACT_SHIFT)+1)) //#define LL2FRACT_ROUND2(VAR) (((VAR)&(1UL<<(FRACT_SHIFT))?(VAR)>>(FRACT_SHIFT+1):((VAR)>>(FRACT_SHIFT+1))+1)) #pragma inline=forced static inline FRACT LL2FRACT_ROUND(long long r) { asm("LSRS %L0,%L0,%1":"+Rp"(r):"I"(FRACT_SHIFT):"cc"); //:); asm("ORR %L0,%L0,%H0, LSL %1":"+Rp"(r):"I"(32-FRACT_SHIFT)); asm("IT CS\n" "ADDCS %L0,%L0,#+1":"+Rp"(r)); return r; } #pragma inline=forced static inline FRACT LL2FRACT_ROUND2(long long r) { asm("LSRS %L0,%L0,%1":"+Rp"(r):"I"(FRACT_SHIFT+1):"cc"); //:); asm("ORR %L0,%L0,%H0, LSL %1":"+Rp"(r):"I"(32-(FRACT_SHIFT+1))); asm("IT CS\n" "ADDCS %L0,%L0,#+1":"+Rp"(r)); return r; } #pragma inline=forced static inline FRACT FMULL(long a, long b) { long long r = MULLS(a,b); return LL2FRACT_ROUND(r); } #pragma inline=forced static inline void Vector_Cross_Product(FRACT * vectorOut, FRACT const * v1, FRACT const * v2) { vectorOut[0]= FMULL(v1[1],v2[2]) - FMULL(v1[2],v2[1]); vectorOut[1]= FMULL(v1[2],v2[0]) - FMULL(v1[0],v2[2]); vectorOut[2]= FMULL(v1[0],v2[1]) - FMULL(v1[1],v2[0]); } static inline FRACT Vector_Dot_Product(FRACT const * vector1, FRACT const * vector2) { long long r; asm("SMULL %L0,%H0,%1,%2":"=Rp"(r):"r"(vector1[0]),"r"(vector2[0])); asm("SMLAL %L0,%H0,%1,%2":"+Rp"(r):"r"(vector1[1]),"r"(vector2[1])); asm("SMLAL %L0,%H0,%1,%2":"+Rp"(r):"r"(vector1[2]),"r"(vector2[2])); return LL2FRACT_ROUND(r); } #pragma inline=forced static inline FRACT Vector_Dot_Product_Half(FRACT const * vector1, FRACT const * vector2) { long long r; asm("SMULL %L0,%H0,%1,%2":"=Rp"(r):"r"(vector1[0]),"r"(vector2[0])); asm("SMLAL %L0,%H0,%1,%2":"+Rp"(r):"r"(vector1[1]),"r"(vector2[1])); asm("SMLAL %L0,%H0,%1,%2":"+Rp"(r):"r"(vector1[2]),"r"(vector2[2])); return LL2FRACT_ROUND2(r); }
Обратите внимание даже не на SMULL/SMLAL, а на IT CS/ADD
Или
#define PRAMP() asm("ADD.N %0,%1":"+r"(sample):"r"(pwm_mask)); #define MRAMP() PRAMP() #define PROCESS() \ asm("ANDS.N %0,%1":"+r"(i1):"r"(pwm_mask)); \ asm("ADD.N %0,%1":"+r"(i1):"r"(sample)); \ *p++=i1; \ i=BLOCK_SIZE; do { sample=*input++; PROCESS(); PRAMP(); PROCESS(); PRAMP(); PROCESS(); PRAMP(); PROCESS(); PRAMP(); PROCESS(); PRAMP(); PROCESS(); PRAMP(); PROCESS(); PRAMP(); PROCESS(); MRAMP(); PROCESS(); MRAMP(); PROCESS(); MRAMP(); PROCESS(); MRAMP(); PROCESS(); MRAMP(); PROCESS(); MRAMP(); PROCESS(); MRAMP(); PROCESS(); } while(--i);
В общем - любим, умеем, практикуем, но в первую очередь стараемся не плодить кучу такого кода.
-
15 minutes ago, Arlleex said:
В Cortex-M4 есть инструкции, которые могут за один проход сравнить соответствующие полуслова в двух регистрах или группу по 4 байта в двух регистрах
Хотя это больше к вопросу о равномерности времени выполнения функции поиска, (детерминированности, что ли)...
Это же и есть O(N). Т.е. время будет пропорционально количеству отсчетов. Коэффициент пропорциональности зависит от оптимизации в том числе, но куда полезнее подумать о возможности переделать алгоритм так, чтобы он превратился, например, в O(log2(N)). Думать надо вот в какую сторону - поиск максимума в отсортированном массиве - O(1). Можно считать - бесплатно. Прямой поиск - O(N). Возможно есть какие-то априорные знания о массиве, какие-то способы предсортировки данных, etc
Просто может так оказаться, что завтра N будет равно не 512, а 4096, и никакой прямой поиск, написанный на ассемблере, не спасет.
-
52 minutes ago, jcxz said:
Вариант в лоб с кучей функций вызываемых через указатели - это пожалуй самый тормозной будет.
Нет, если установленных в 1 бит немного. Куда быстрее, чем куча if'ов.
1 hour ago, jcxz said:Через LDM невозможно, так как переменные var0, ... раскиданы в памяти произвольным образом. varX - это условно так обозначено, чтобы описать задачу. А в общем случае - это могут быть и отдельные члены разных классов или структур.
Простите, а кто вообще этот протокол обмена придумал? Зачем такие безумные сложности?
-
Продолжаем разговор ;)
11 hours ago, jcxz said:Есть массив из 512-и 16-битных беззнаковых чисел. Нужно найти максимальное число в этом массиве.
Вот тут я бы пересмотрел вообще саму идеологию. Все эти прямые поиски - они все равно O(N), хоть на асме, хоть на Си. Как данные в массив попадают? Может быть их имеет смысл как-то предсортировать, если они попадают в массив малыми порциями, и этим вообще глобально улучшить ситуацию?
-
6 hours ago, gosha-z said:
production вообще-то...
Это у программистов нынче такой новояз. Они обычно себя обзывают software product development company, но частенько слово development опускают.
-
Судя по 10В/м - это воздействие радиочастотных полей. Не должно нарушаться функционирование устройства. Походу местный дурачок неправильно заполнил протокол.
-
Кстати, господа, пардон во втором примере за безумные приведения к FiiFunc*, но я просто не соображу, можно ли описать тип указателя на функцию, в которой один из параметров - указатель на такую функцию.
-
9 hours ago, jcxz said:
вот другой пример: Есть код, который состоит из длинного полотенца:
Мне кажется, Вы сильно загоняетесь.
Решение в лоб:
unsigned long vars[64]; #define PROC(B,T,N) \ if (mask&(1UL<<B)) {T *_d; _d=d; *_d++=vars[N]; d=_d;} void f(unsigned long mask, void *d) { PROC(0,long,0); PROC(1,short,1); PROC(2,long,2); PROC(3,long,3); PROC(4,short,4); PROC(5,short,5); PROC(6,long,6); PROC(7,short,7); }
дает вполне вменяемый результат:
Spoiler\ In section .bss, align 4 2 unsigned long vars[64]; \ vars: \ 0x0 DS8 256 3 4 #define PROC(B,T,N) \ 5 if (mask&(1UL<<B)) {T *_d; _d=d; *_d++=vars[N]; d=_d;} 6 \ In section .text, align 2, keep-with-next 7 void f(unsigned long mask, void *d) 8 { 9 PROC(0,long,0); \ f: (+1) \ 0x0 0x.... LDR.N R2,??DataTable1 \ 0x2 0x07C3 LSLS R3,R0,#+31 \ 0x4 0xBF44 ITT MI \ 0x6 0xF8D2 0xC000 LDRMI R12,[R2, #+0] \ 0xA 0xF841 0xCB04 STRMI R12,[R1], #+4 10 PROC(1,short,1); \ 0xE 0x0783 LSLS R3,R0,#+30 \ 0x10 0xBF44 ITT MI \ 0x12 0xF8D2 0xC004 LDRMI R12,[R2, #+4] \ 0x16 0xF821 0xCB02 STRHMI R12,[R1], #+2 11 PROC(2,long,2); \ 0x1A 0x0743 LSLS R3,R0,#+29 \ 0x1C 0xBF44 ITT MI \ 0x1E 0xF8D2 0xC008 LDRMI R12,[R2, #+8] \ 0x22 0xF841 0xCB04 STRMI R12,[R1], #+4 12 PROC(3,long,3); \ 0x26 0x0703 LSLS R3,R0,#+28 \ 0x28 0xBF44 ITT MI \ 0x2A 0xF8D2 0xC00C LDRMI R12,[R2, #+12] \ 0x2E 0xF841 0xCB04 STRMI R12,[R1], #+4 13 PROC(4,short,4); \ 0x32 0x06C3 LSLS R3,R0,#+27 \ 0x34 0xBF44 ITT MI \ 0x36 0xF8D2 0xC010 LDRMI R12,[R2, #+16] \ 0x3A 0xF821 0xCB02 STRHMI R12,[R1], #+2 14 PROC(5,short,5); \ 0x3E 0x0683 LSLS R3,R0,#+26 \ 0x40 0xBF44 ITT MI \ 0x42 0xF8D2 0xC014 LDRMI R12,[R2, #+20] \ 0x46 0xF821 0xCB02 STRHMI R12,[R1], #+2 15 PROC(6,long,6); \ 0x4A 0x0643 LSLS R3,R0,#+25 \ 0x4C 0xBF44 ITT MI \ 0x4E 0xF8D2 0xC018 LDRMI R12,[R2, #+24] \ 0x52 0xF841 0xCB04 STRMI R12,[R1], #+4 16 PROC(7,short,7); \ 0x56 0x0600 LSLS R0,R0,#+24 \ 0x58 0xBF44 ITT MI \ 0x5A 0x69D2 LDRMI R2,[R2, #+28] \ 0x5C 0x800A STRHMI R2,[R1, #+0] 17 } \ 0x5E 0x4770 BX LR ;; return
Тут, конечно, может возникнуть вопрос другого характера. Например, если почти все параметры используются, то грузить их в регистры при помощи LDM будет малость эффективнее. А вот у IAR'а с использованием LDM как-то не сложилось, черт его знает, почему.
Но возможен другой вариант. Допустим, что из всего списка в реальности надо вообще всего пару-тройку параметров генерить. Тогда куда более эффективным решением будет такое:
typedef void (*FillFunc)(void *, void *, long *); #define GLUE(A,B) A##B #define FillParam(T,N) \ void GLUE(FillParam,N)(void *functab, void *d, long *s) \ { \ T *_d; \ _d=d; \ *_d++=s[N]; \ FillFunc *_functab=functab; \ FillFunc nf=*_functab++; \ nf(_functab,_d,s); \ } FillParam(long,0) FillParam(short,1) FillParam(long,2) FillParam(short,3) void FillParamEnd(void *functab, void *d, long *s) { } FillFunc FillerTask[]= { FillParam0,FillParam1,FillParam2,FillParam3, FillParamEnd }; void FillParamBegin(void *d, long *s) { FillFunc *functab=FillerTask; FillFunc nf=*functab++; nf((void*)functab,d,s); }
Результат как на асме:
Spoiler19 typedef void (*FillFunc)(void *, void *, long *); 20 21 #define GLUE(A,B) A##B 22 23 #define FillParam(T,N) \ 24 void GLUE(FillParam,N)(void *functab, void *d, long *s) \ 25 { \ 26 T *_d; \ 27 _d=d; \ 28 *_d++=s[N]; \ 29 FillFunc *_functab=functab; \ 30 FillFunc nf=*_functab++; \ 31 nf(_functab,_d,s); \ 32 } 33 \ In section .text, align 2, keep-with-next 34 FillParam(long,0) \ FillParam0: (+1) \ 0x0 0x6813 LDR R3,[R2, #+0] \ 0x2 0xF841 0x3B04 STR R3,[R1], #+4 \ 0x6 0xF850 0x3B04 LDR R3,[R0], #+4 \ 0xA 0x4718 BX R3 \ In section .text, align 2, keep-with-next 35 FillParam(short,1) \ FillParam1: (+1) \ 0x0 0x6853 LDR R3,[R2, #+4] \ 0x2 0xF821 0x3B02 STRH R3,[R1], #+2 \ 0x6 0xF850 0x3B04 LDR R3,[R0], #+4 \ 0xA 0x4718 BX R3 \ In section .text, align 2, keep-with-next 36 FillParam(long,2) \ FillParam2: (+1) \ 0x0 0x6893 LDR R3,[R2, #+8] \ 0x2 0xF841 0x3B04 STR R3,[R1], #+4 \ 0x6 0xF850 0x3B04 LDR R3,[R0], #+4 \ 0xA 0x4718 BX R3 \ In section .text, align 2, keep-with-next 37 FillParam(short,3) \ FillParam3: (+1) \ 0x0 0x68D3 LDR R3,[R2, #+12] \ 0x2 0xF821 0x3B02 STRH R3,[R1], #+2 \ 0x6 0xF850 0x3B04 LDR R3,[R0], #+4 \ 0xA 0x4718 BX R3 38 \ In section .text, align 2, keep-with-next 39 void FillParamEnd(void *functab, void *d, long *s) 40 { 41 } \ FillParamEnd: (+1) \ 0x0 0x4770 BX LR ;; return 42 \ In section .data, align 4 43 FillFunc FillerTask[]= \ FillerTask: \ 0x0 0x....'.... DC32 FillParam0, FillParam1, FillParam2, FillParam3, FillParamEnd \ 0x....'.... \ 0x....'.... \ 0x....'.... \ 0x....'.... 44 { 45 FillParam0,FillParam1,FillParam2,FillParam3, 46 FillParamEnd 47 }; 48 \ In section .text, align 2, keep-with-next 49 void FillParamBegin(void *d, long *s) 50 { \ FillParamBegin: (+1) \ 0x0 0x460A MOV R2,R1 51 FillFunc *functab=FillerTask; 52 FillFunc nf=*functab++; 53 nf((void*)functab,d,s); \ 0x2 0x.... LDR.N R3,??DataTable1_1 \ 0x4 0x4601 MOV R1,R0 \ 0x6 0x1D18 ADDS R0,R3,#+4 \ 0x8 0x681B LDR R3,[R3, #+0] \ 0xA 0x4718 BX R3 54 }
Естественно, FillerTask можно сгенерить с нужной Вам периодичностью из редко изменяемой маски.
Ну и, конечно, возможна вообще циничная генерация самомодифицирующегося кода из команд LDR R2,[R0,#+disp] и STR(H) R2,[R1],#4(2). Его генерация отлично на Си пишется. И как бы не смешно это звучало, но это будет самый оптимальный вариант (ну, правда, максимум может понадобится 64*6+2=386 байт ОЗУ для хранения генерируемого кода.
-
Moderator: Пока закреплять особо нечего. Наполнится - сделаю.
-
7 hours ago, Politeh said:
1. Должна быть
Простите, кто кому что должен? Тут так не принято, тут помогают на добровольной основе. Либо Вы
1. можете собрать такой материал и выложить его в общий доступ на добровольной основе.
2. можете задавать прямые вопросы в отдельных темах и получать на них ответы "гуру" на добровольной основе.
3. можете заплатить профессионалам, они сделают для Вас "дорожную карту" по борьбе за ЭМС. Заплатить, конечно, на добровольной основе.
-
5 hours ago, Petka said:
мультикаст в данной задаче не поможет?
Не знаю, возможно и да. Решение конкретно этой проблемы пока отложено на будущее.
-
Все, повеселились и хватит. Закрыто.
-
10 hours ago, haker_fox said:
А реально ли для синтеза использовать Cortex-M4F или такие вещи нужно делать на ЦСП? И если нужен сигнальный процессор, то на какие модели смотреть, ибо я в них не копенгаген) И да, это интерес чисто личный, не коммерческий, поэтому вопрос цены и эффективности пока не стоит...
Вот тот самый Pianoteq есть для Linux под ARM, работает на Raspberry Pi. Это, конечно, не M4F, но таки ARM ;)
-
Есть и чисто софтовые. Имеется в виду в виде VSTi.
Есть, например, Pianoteq (https://www.modartt.com/), довольно давно его уже пилят. Это рояль моделирующий. Правда, вроде там самые атаки именно семплами сделаны, но сустейн именно моделирование.
А еще есть ребята Audio Modeling SWAM (https://audiomodeling.com/). Там столько параметров, что приходится специальные контроллеры использовать для прописывания партий, одной клавиатурой (имеется в виду MIDI-клавиатура) не обойдешься:
Некоторые целую струнную группу БСО ухитрились вот так прописать
Только не спрашивайте, как и что там сделано, не дизассемблировал ;)
-
Moderator: Простите, а причем тут Matlab?
-
Moderator: Пусть повисит тема немного, а потом снесем. Я бы сразу ее в оффтопик перенес, но тогда ТС утратит возможность доступа к теме.
-
23 minutes ago, iiv said:
Технический репорт пишу с описанием того, что делаю.
Я имею в виду к какой области относится Ваше изобретение или что там. Для чего применяется? Одно дело - несущую в телеграфном передатчике умножать, а другое - музыку питчшифтить.
-
36 minutes ago, iiv said:
Мне же нужно, чтобы исходный сигнал был какой есть (обычно там множество различных частот), и этот умножитель действует на все частоты с одинаковым коэффициентом...
В области обработки аудио-сигналов есть такой термин, как pitch shift. Тоже самое, но с другого боку (оставить частоты теми же, а изменить длительность) - это time stretching. Вам в каком вообще контексте термин нужен?
-
21 hours ago, SVNKz said:
Попробуйте вариант проверки линейно нарастающим напряжением, треугольным, с выхода ЦАП, проверить его можно путём измерения ступенек напряжения на выходе высокоточным вольтметром.
Вариант проверки чего? АЦП? Вы шутите? Там 120дБ ДД. С выхода какого ЦАП предлагаете взять такую пилу? И каким "высокоточным" вольтметром измерить ее "ступеньки"? 6 знаков минимум надо, а лучше бы 7.
И да, там ухудшаются характеристики на постоянном токе. Полоса ниже 20Гц в аудио-применениях не волнует от слова совсем.
-
3 hours ago, shkal said:
просто купите генератор Виктора на ebay
В самом начале я про него говорил:
-
29 minutes ago, jcxz said:
Это так можно только если действительно можно не записывать старшие 16 бит. Я выше уже писал об этом.
Я так думаю, что если сдуру там и сделано 32 бита только, то можно писать не 0 и 0xFFFF, а 0 и 0xFFFFFFFF почти наверняка.
-
Опубликовано · Изменено пользователем Rst7 · Пожаловаться
Самый быстрый способ могу предложить только такой:
SBFX R1,R0,#0,#1 STRH R1,[R2,#0] SBFX R1,R0,#1,#1 STRH R1,[R2,#2] .... SBFX R1,R0,#7,#1 STRH R1,[R2,#14]
По два такта на пиксель.
Это вполне и при помощи GCC inline asm делается, так что можно обойтись без отдельного модуля на ассемблере.
-
Навык анализа листингов
в Программирование
Опубликовано · Пожаловаться
И возвращаясь к передаче кучи переменных.
Конечно, протокол обмена надо делать другим. Сначала складывать все long, потом все short. Итого код выглядит так:
Самое занятное - это результат компиляции такого тупого кода:
Если разворота циклов, сделанных самим компилятором, недостаточно, то можно и самому выступить по написанию Duff Device, что несложно. Но и этот код, прямо скажем, хуже совсем на копейку, нежели JIT, но на порядок проще.