Ардуина попала под ссанкции? Хм. Походу, это уже наши тормозят. Есть немало примеров, когда доступ к безобидным материалам закрывают с нашей стороны по формальным признакам, находя какие-то древние и неактуальные материалы, в которых чето там "усматривают". Очень у нас уж любят всё запрещать из-за собственного страха.
А что будет дальше - да и так примерно понятно, запретят всё забугорное (в первый раз чтоль?) и принудительно влепят какой-нить условный Миландр по цене десять тысяч шкурок енотов за штучку. И покупать разрешат только при наличии справки из комендатуры. Да у них уже несколько лет так и сделано.
Касательно затронутой темы Асм/Си.
Сделал вот такой синтетический пример на Си. Вычисление среднего арифметического в массиве чисел. Функция Average() вызывает функцию Sum() для подсчета суммы элементов и этот результат делит на число элементов в массиве.
Спойлер
Код: Выделить всё
int Sum(int const* array, uint32_t n)
{
int result = 0;
while(n--)
result += *array++;
return result;
}
int Average(int const* array, uint32_t n)
{
return Sum(array, n) / n;
}
int array[50];
int main()
{
volatile int avr;
avr = Average(array, 50);
При компиляции без оптимизации (параметр -O0) получается вот такой ассемблерный листинг, и он довольно длинный
Спойлер
Код: Выделить всё
int Sum(int const* array, uint32_t n)
{
800014c: b480 push {r7}
800014e: b085 sub sp, #20
8000150: af00 add r7, sp, #0
8000152: 6078 str r0, [r7, #4]
8000154: 6039 str r1, [r7, #0]
int result = 0;
8000156: 2300 movs r3, #0
8000158: 60fb str r3, [r7, #12]
while(n--)
800015a: 683b ldr r3, [r7, #0]
800015c: 1e5a subs r2, r3, #1
800015e: 603a str r2, [r7, #0]
8000160: 2b00 cmp r3, #0
8000162: bf14 ite ne
8000164: 2301 movne r3, #1
8000166: 2300 moveq r3, #0
8000168: b2db uxtb r3, r3
800016a: 2b00 cmp r3, #0
800016c: d007 beq.n 800017e <_Z3SumPKim+0x32>
result += *array++;
800016e: 687b ldr r3, [r7, #4]
8000170: 1d1a adds r2, r3, #4
8000172: 607a str r2, [r7, #4]
8000174: 681b ldr r3, [r3, #0]
8000176: 68fa ldr r2, [r7, #12]
8000178: 4413 add r3, r2
800017a: 60fb str r3, [r7, #12]
while(n--)
800017c: e7ed b.n 800015a <_Z3SumPKim+0xe>
return result;
800017e: 68fb ldr r3, [r7, #12]
}
8000180: 4618 mov r0, r3
8000182: 3714 adds r7, #20
8000184: 46bd mov sp, r7
8000186: bc80 pop {r7}
8000188: 4770 bx lr
0800018a <_Z7AveragePKim>:
int Average(int const* array, const uint32_t n)
{
800018a: b580 push {r7, lr}
800018c: b082 sub sp, #8
800018e: af00 add r7, sp, #0
8000190: 6078 str r0, [r7, #4]
8000192: 6039 str r1, [r7, #0]
return Sum(array, n) / n;
8000194: 6839 ldr r1, [r7, #0]
8000196: 6878 ldr r0, [r7, #4]
8000198: f7ff ffd8 bl 800014c <_Z3SumPKim>
800019c: 4603 mov r3, r0
800019e: 461a mov r2, r3
80001a0: 683b ldr r3, [r7, #0]
80001a2: fbb2 f3f3 udiv r3, r2, r3
}
80001a6: 4618 mov r0, r3
80001a8: 3708 adds r7, #8
80001aa: 46bd mov sp, r7
80001ac: bd80 pop {r7, pc}
...
080001b0 <main>:
int main()
{
volatile int avr;
avr = Average(array, 50);
80001b6: 2132 movs r1, #50 ; 0x32
80001b8: 4802 ldr r0, [pc, #8] ; (80001c4 <main+0x14>)
80001ba: f7ff ffe6 bl 800018a <_Z7AveragePKim>
80001be: 4603 mov r3, r0
80001c0: 607b str r3, [r7, #4]
Подробно каждую строчку описывать не буду, это долго. Скажу лишь что здесь при генерации компилятор использовал самый простой и избыточный шаблон, сохраняя все вызовы функций вместе с передачей параметров через стек и самые простые алгоритмы математики и логики, даже несмотря на более оптимальный сишный код. Кароч, компилятор исполняет роль тупого студента.
Ладно. Теперь включаем оптимизацию компиляции на уровень -O3 и получаем:
Спойлер
Код: Выделить всё
800014c: 2200 movs r2, #0
800014e: 4b07 ldr r3, [pc, #28] ; (800016c <main+0x20>)
8000152: f103 00c8 add.w r0, r3, #200 ; 0xc8
8000156: f853 1b04 ldr.w r1, [r3], #4
800015a: 4283 cmp r3, r0
800015c: 440a add r2, r1
800015e: d1fa bne.n 8000156 <main+0xa>
8000160: 4b03 ldr r3, [pc, #12] ; (8000170 <main+0x24>)
8000162: fba3 2302 umull r2, r3, r3, r2
8000166: 091b lsrs r3, r3, #4
8000168: 9301 str r3, [sp, #4]
Здесь уже задействуются более эффективные шаблоны. При этом вызовы функций Average и Sum с их накладными расходами полностью исчезают. Компилятор учитывает короткую сишную запись while(n--) и *array++ и применяет соответствующие совмещенные инструкции.
Первые три строчки задают начальные условия, следующие четыре строчки выполняют суммирование элементв и последние четыре строки выполняют деление суммы на число элементов и сохренение результата в ОЗУ.
Таким образом, при включении оптимизации компилятора на выходе генерируется фактически то же самое, как если бы вы писали это вручную на ассемблере. Возможно, кому-то покажется быстрее написать этот текст на ассемблере. Конкретно этот пример несложен и на ассемблере писать даже меньше букв, чем на Си.
Но чтобы писать такой же эффективный код на ассемблере в рамках всей программы, нужно помимо логики приложения всегда держать в голове логику и ограничения инструкций, помнить все их варианты и ограничения параметров. А во-вторых, изменение такого текста под изменившиеся условия будет выполнить намного сложнее.
В разных сериях ядра АРМ используется разный набор инструкций. В лучшем случае, если замените Cortex M3 на Cortex M7 вы просто ограничитесь базовым набором, не используя специфические для M7 инструкции. А вот при обратном переходе, если использовали расширенный набор для M7, придется убирать их и искать упрощенный эквивалент на наборе M3.
В противовес этому, когда пишите на Си, один и тот же код без изменений будет работать на любом Кортексе. Я не имею ввиду аппаратные различия периферии, а вот такую прикладную задачу.
Как-то так.