Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=3936170#p3936170"]Очень простой язык (чуть сложней ассемблера, зато писанины поменьше, но при этом остается понимание).[/uquote]Сложный язык (сложней С, зато возможностей побольше, и при этом писанины поменьше). Смотри как лаконично записан цикл for по всему массиву. Просто взяли ссылку на каждый элемент массива и отпечатали по ней в терминал. А сортировка массива на этапе компиляции как тебе? И строка форматирования вывода (шаблон от строки на секундочку), держу пари, сильно оптимальней того что printf-ом бы получилось. Reflector столько плюшек в такой маленький пример засунул! Только жаль не все оценить могут.
Реклама
iddqd
Нашел транзистор. Понюхал.
Сообщения: 156
Зарегистрирован: Вс сен 06, 2020 16:06:10

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение iddqd »

C++ вариант ногодрыжной либы самый умный и эффективный, оптимизирует как на уровне пинов, так и на уровне работы с регистрами.
Там где мне вот именно перфоманс (а может и размер кода) важен, я вообще скажу reg32_write(reg, val) на какой-нибудь BSRR. И это будет чуть не 1 инструкция асма, без гребаных мегалиб и кучи кода. А, хотите сказать что это выглядит как кал? Согласен! Поэтому #define SOMETHING_ON ... вон то, с правильными параметрами. Выглядит лучше, понятно что и нафига. И по прежнему чуть не 1 команда асма. И те параметры конечно же символическими константами оформить, а не волшебными числами.
Можешь попытаться на его основании создать реверсный массив который также будет размещен во флеше.
А мне это нафига? Если мне что-то такое приспичит я подумаю о том чтобы хранить 1 массив а в месте где инверсный надо - индекс сделать не x а (arr_size - x). Вы там можете монстра с темплейтами воротить, а я пробурчу "оверинженерия сосет". К тому же в этом коде потом ардуинщик "типа знающий плюсы" дров наломает мама не горюй, потому что оказывается что C++ вовсе и не яваскрипт, а ардуинистый субдиалект далеко и не единственный вариант.
Какая разница менюшка или не менюшка, С++ умеет выполнять код на этапе компиляции,
И вот именно такие выкрутасы я абсолютно не желаю видеть, это порой делает происходящее чертовски неочевидным. И когда это прошивка МК это по мне довольно дерьмово. Есть шанс что код на этой почве поймут не так как это было задумано.
У gcc есть атрибут section(".init"), помечая им сишную функцию можно заставить ее вызываться в начале выполнения программы, для чего используется тот же механизм, что и для конструкторов, т.е. типичный gcc стартап для С и С++ ничем не отличается. Естественно атрибут эмуллирующий деструкторы имеется тоже.
Для сей я могу написать стартап сам. Для плюсов я это не сделать не возьмусь. А молиться на неведомы черные ящики делающие неведомо что лично мне в микроконтроллерах очень неохота. Хочу знать что и почему происходит, это дает мне плотный контроль над происходящим. Вот лично вы смогете накорябать плюсам стартап? А может еще и на плюсах?! А то сям на сях - можно. На кортексах без ассемблера вообще, что прикольно.
Насколько тривиально на С все размудрить для таких списков пинов?
Оно и на сях придет к чему-то весьма культурному, если не страдать фигней. Допустим вообще led7_out(digit). Внутри может быть по разному. И то что оно внутрях возьмет какой там еще SEVENSEG_PIN0 ... PIN7 из какого-нибудь board.h определяющего мой фактический борд, и перекраиваемый под новый за минуту - а оно при переделке борда проблемой уже не будет. И с новой бордой - ну переопределить пины, остальное и не заметит что что-то поменялось. А то что я не городил адские мегаструктуры - и чего?
В IAR и Keil стартап по ResetHandler передаёт управление стандартной библиотеке. Она сама знает есть ли конструкторы и вызывает их.
Вот именно это мне и не нравится. Есть какие-то волшебники, рангом покруче вас, которые вот так могут. А вот лично вы понятия не имеете что они делают, как это работает, но вы почему-то типа круче. Ага, конечно, размечтались. Вот чем мне ассемблерщики нравятся - не верят в черную магию черных ящиков. И знают что у них внутри.
Ничуть не больше чем на Си.
Не, вот пардон, когда вы запуск другой фирмари на чем-то сиобразном написали, вы таки чекали что в дампе. А я корябнув интринсик volatile asm так не развлекался, потому что вот он точно будет таким как надо, и компилер уже не имеет права там сумничать. У меня 0 раз, у вас 1.
А почему должно быть иначе, если вы не знаете язык?
У сей и тут есть преимущество: относительно простые. Да, есть премудрости и подводные камни. Но в плюсах этого счастья еще в цать раз больше - достаточно сравнить допустим правила MISRA для C и C++ - и подохренеть малость с того какой си++ простой и офигенный для писания программ без ошибок, что способов прострелить пятку в десяток раз больше. И интересно сколько упражнений местных вообще пройдут проверку такими тулзами без мата статического анализатора.
Реклама
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение Reflector »

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]Там где мне вот именно перфоманс (а может и размер кода) важен, я вообще скажу reg32_write(reg, val) на какой-нибудь BSRR. И это будет чуть не 1 инструкция асма, без гребаных мегалиб и кучи кода.[/uquote]
Эта reg32_write начнет проигрывать С++ мегалибе уже на установке одного единственного бита и дальше будет только хуже:

Код: Выделить всё

GPIOC->BSRR = GPIO_BSRR_BS15;          
                                       
5D 4B                ldr r3, [pc, #372]
4F F4 00 42          mov.w r2, #32768  
9A 61                str r2, [r3, #24] 

Код: Выделить всё

PC15::set();                           
5E 4B                ldr r3, [pc, #376]
80 26                movs r6, #128     
5E 76                strb r6, [r3, #25]
А мне это нафига?
Чтобы подтвердить свои слова о том, что на С наверно так тоже можно. Ну нельзя так нельзя :)
И вот именно такие выкрутасы я абсолютно не желаю видеть, это порой делает происходящее чертовски неочевидным. И когда это прошивка МК это по мне довольно дерьмово. Есть шанс что код на этой почве поймут не так как это было задумано.
Массив описывающий менюшку трансформируется на этапе компиляции и ложится во флеш, если компилятор так не сможет сделать, то код не скомпилируется, потому в принципе не может быть такого что пользователь сделал что-то не так и выполнение кода трансформации незаметно перешло в рантайм.
Для сей я могу написать стартап сам. Для плюсов я это не сделать не возьмусь. Вот лично вы смогете накорябать плюсам стартап? А может еще и на плюсах?! А то сям на сях - можно.
Стартап на C++ для целого STM32H7, вектора прерываний всегда в RAM, код в RAM или флеш:
Спойлер

Код: Выделить всё

#include <stm32h7xx.h>
#include "config.h"

extern void *_estack;

extern "C" void Reset_Handler();
extern "C" void Default_Handler();
int main();

using FP = void(*)();

#ifdef sram_layout
FP isrVectors[166] __attribute__((section(".isr_vector_ram"), used))
{
	(FP)&_estack,
	&Reset_Handler
};
#else
FP isrVectors[166] __attribute__((section(".isr_vector_ram"), used));

FP fvectors[] __attribute__((section(".isr_vector"), used)) =
{
	(FP)&_estack,
	&Reset_Handler,
};
#endif

void setVectorTable(IRQn_Type irqn, FP fp)
{
	isrVectors[int(irqn) + 16] = FP(fp);
	__DSB();
	__ISB();
}

extern uint8_t _data_load, _data, _data_size;
extern uint8_t _bss, _bss_size;
extern uint8_t _itcm_load, _itcm, _itcm_size;
extern uint8_t _itcm_bss, _itcm_bss_size;
extern uint8_t _dtcm_load, _dtcm, _dtcm_size;
extern uint8_t _dtcm_bss, _dtcm_bss_size;
extern uint8_t _sram123_load, _sram123, _sram123_size;
extern uint8_t _sram123_bss, _sram123_bss_size;
extern uint8_t _sram4_load, _sram4, _sram4_size;
extern uint8_t _sram4_bss, _sram4_bss_size;

void SystemInit()
{
	SCB->CPACR = SCB->CPACR | (3 << 10 * 2) | (3 << 11 * 2);  // set CP10 and CP11 Full Access
	
	RCC->CR = RCC->CR | RCC_CR_HSION;
    RCC->CFGR = 0;
 	RCC->CR = RCC->CR & ~(RCC_CR_HSEON | RCC_CR_CSSHSEON | RCC_CR_CSION | RCC_CR_HSI48ON | RCC_CR_CSIKERON | RCC_CR_PLL1ON | RCC_CR_PLL2ON | RCC_CR_PLL3ON);

    RCC->D1CFGR = 0;
    RCC->D2CFGR = 0;
    RCC->D3CFGR = 0;
    RCC->PLLCKSELR = 0;
    RCC->PLLCFGR   = 0;
    RCC->PLL1DIVR  = 0;
    RCC->PLL1FRACR = 0;
    RCC->PLL2DIVR  = 0;
    RCC->PLL2FRACR = 0;
    RCC->PLL3DIVR  = 0;
    RCC->PLL3FRACR = 0;
 	RCC->CR = RCC->CR & ~RCC_CR_HSEBYP;
    RCC->CIER = 0;

	RCC->AHB2ENR = RCC->AHB2ENR | RCC_AHB2ENR_SRAM1EN | RCC_AHB2ENR_SRAM2EN | RCC_AHB2ENR_SRAM3EN;
	RCC->AHB2ENR;
	
	PWR->CR3 = PWR->CR3 & ~(PWR_CR3_SCUEN | PWR_CR3_BYPASS) | PWR_CR3_LDOEN;
	while (!(PWR->CSR1 & PWR_CSR1_ACTVOSRDY)) {}
	
#ifndef sram_layout
	memcpy(&_data, &_data_load, (size_t)&_data_size);
	memcpy(&_itcm, &_itcm_load, (size_t)&_itcm_size);
	memcpy(&_dtcm, &_dtcm_load, (size_t)&_dtcm_size);
	memcpy(&_sram123, &_sram123_load, (size_t)&_sram123_size);
	memcpy(&_sram4, &_sram4_load, (size_t)&_sram4_size);
#endif

	memset(&_bss, 0, (size_t)&_bss_size);
	memset(&_itcm_bss, 0, (size_t)&_itcm_bss_size);
	memset(&_dtcm_bss, 0, (size_t)&_dtcm_bss_size);
	memset(&_sram123_bss, 0, (size_t)&_sram123_bss_size);
	memset(&_sram4_bss, 0, (size_t)&_sram4_bss_size);

	SCB->VTOR = uint32_t(isrVectors);

	for (int i = 2; i < 166; i++)
	{
		isrVectors[i] = FP(Default_Handler);
	}

	__DSB();
	__ISB();
}

extern "C" void __libc_init_array();

void __attribute__((naked, noreturn)) Reset_Handler()
{
	asm("ldr sp, =_estack");
	__ISB();

	SystemInit();
	__libc_init_array();

	main();
	while (true) {}
}

void Default_Handler() { __BKPT(255); }
Я его чуть обрезал, от сишного стартапа отличия минимальны, сделано на основе стандартного сишного стартапа из visualgdb.
Оно и на сях придет к чему-то весьма культурному, если не страдать фигней.
На С проблема даже просто весьма культурно передать 12 пинов с разных портов... Была относительно недавно тема про семисегментники, пишущие на С там перебирали пины из массива и выводили по одному биту :)
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]Там где мне вот именно перфоманс (а может и размер кода) важен, я вообще скажу reg32_write(reg, val) на какой-нибудь BSRR.[/uquote]И получите неоптимальный код. Потому что
[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]И это будет чуть не 1 инструкция асма,[/uquote]это не будет одна инструкция. Это будет загрузка адреса BSRR в РОН и загрузка val в другой РОН. С последующей командой STR. Это если reg32_write в той же единице трансляции находится. А то ещё ведь ещё и её вызов может произойти. А C++ метод на этапе компиляции сначала проверит, а не совпадает ли маска выводимых данных с 0xFF, 0xFFFF. Тогда И BSRR никакой не нужен, а можно командой STRB или STRH прямо байт или слово в ODR пульнуть. Но, допустим, счастья не случилось и надо писать в BSRR. Опять начинаем анализ записываемых данных с целью определить, нельзя ли обойтись командами STRB или STRH. Потому что, если вспомнить систему команд ARM (да, да, С++ программисты её знают), то константы меньшей разрядности загружаются в РОН проще, что приводит к более быстрому и компактному коду. А так как методы класса статические, описаны в заголовочном файле, то всё гарантировано заинлайнится. И вот тогда действительно будет всего несколько ассемблерных инструкций. Звучит сложно и как фантастика, но на деле все просто. Пример делает 10 импульсов на PA9.

Код: Выделить всё

//Repeat<10>([]{ PA_9::set(); PA_9::clear(); });
   MOVS     R0,#+2
   LDR.N    R1,??DataTable1_4  ;; 0x48000019
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
   STRB     R0,[R1, #+0]
   STRB     R0,[R1, #+2]
Хренушки твоя reg32_write(reg, val) вызванная 20 раз даст такой код!

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]А мне это нафига?[/uquote]Стандартный аргумент, когда не можешь. Знакомо.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]К тому же в этом коде потом ардуинщик "типа знающий плюсы" дров наломает мама не горюй,[/uquote]Наоборот. Он не полезет внутрь библиотек, а будет вызывать простые и понятные методе типа serial.begin.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]Есть шанс что код на этой почве поймут не так как это было задумано.[/uquote]Кто поймёт? Код компилятор должен понимать. Мнение безграмотных читателей в топку.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]Для сей я могу написать стартап сам. Для плюсов я это не сделать не возьмусь.[/uquote]Ну, это лишь говорит о полном непонимании вопроса, который вы так многословно обсуждаете. К сообщению приложен стартап для GCC под С и С++. Какая из строчек вам непонятна?

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]Вот лично вы смогете накорябать плюсам стартап? А может еще и на плюсах?! А то сям на сях - можно. На кортексах без ассемблера вообще, что прикольно.[/uquote]А думаете кто мне стартапы пишет? Если бы вы читали форум, а не только писали, то уже давно бы нашли мой иниверсальный стартап для Cortex-M, который совместим с GCC, IAR и Keil.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]
Насколько тривиально на С все размудрить для таких списков пинов?
Оно и на сях придет к чему-то весьма культурному, если не страдать фигней.[/uquote]Вы даже не поняли в чём подвох. Печально.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]
В IAR и Keil стартап по ResetHandler передаёт управление стандартной библиотеке. Она сама знает есть ли конструкторы и вызывает их.
Вот именно это мне и не нравится. Есть какие-то волшебники, рангом покруче вас, которые вот так могут. А вот лично вы понятия не имеете что они делают, как это работает, но вы почему-то типа круче.[/uquote]Когда я лет 20 назад осваивал работу в IAR, то исследовал что делает стартовая библиотека. Смотрел исходники, щупал отладчиком. Пришел к выводу, что там нет ничего лишнего и писали её профи. Именно поэтому для IAR я смело ResetHandler перенаправляю на __cmain и знаю что всё будет Оk.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]Вот чем мне ассемблерщики нравятся - не верят в черную магию черных ящиков. И знают что у них внутри.[/uquote]Вера начинается там где заканчиваются знания. Знания С++ программиста обычно гораздо выше. По крайней мере, тех с кем я сталкивался по жизни. Им не надо верить в чёрную магию, они её сами делают.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937124#p3937124"]И интересно сколько упражнений местных вообще пройдут проверку такими тулзами без мата статического анализатора.[/uquote]Покажите мне как ассемблерные вставки его проходят. Ага.
startup_gcc_stm32f303xc.c
(9.98 КБ) 229 скачиваний
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение AVI-crak »

GCC при сборке Си - закрывает глаза на границы массивов. Записать в массив 20 чисел, когда там всего 10 мест - код соберётся без предупреждений. Это долгоиграющий баг, который в той или иной степени наследуют все языки более сложного уровня. И да, в С++ оно тоже часто прокатывает.
Реклама
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение Reflector »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=3937249#p3937249"]GCC при сборке Си - закрывает глаза на границы массивов.[/uquote]
Была одна тема, там ТС написал:

Код: Выделить всё

char s[5] = "Hello";
В С++ ошибка, как сишный код компилируется даже без предупреждения, по крайней мере если в gcc дополнительные ключи не указывать. Еще недавно столкнулся, в глобальном пространстве имен было типа такого: Это объявление сишной функции для которого забыли в начале void написать, msvc никаких проблем тут не видит, в C++ это естественно ошибка.
Реклама
iddqd
Нашел транзистор. Понюхал.
Сообщения: 156
Зарегистрирован: Вс сен 06, 2020 16:06:10

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение iddqd »

Прошу прощения, подробное и нудное сообщение к сожалению просралось по техническим причинам, второй раз печатать лень, поэтому кратко:
1) Я не понимаю что люди делают с GCC и Си, чтобы "такой код" не генерился. С -O0 собирают? У меня gcc грузит в некий регистр "базу", чуть не 1 раз на всю фирмварь в лучшем случае, и танцует от нее, и не только BSRR но и много чего еще, что в кодирование смещения влезло. А обрашения делает компактно, кодируя в команду компилтайм константы + смещения относительно базы. Примерно это делает и STM'ский boot ROM кстати. Не знаю, си у них там такой аккуратный или таки асм (в F1xx бутром всего 2 кило, я его дизассемблировал более-менее по приколу посмотреть как профи флеш шьют).
2) Кстати в этом gcc легко даст мастеркласс ассемблерщикам, вспомнив через килобайт кода что удачная база в регистре уже была. Ассемблерщику через кило тяжко это трекать.
3) Да, асм не поддается статическому анализу. В нем недостаточно деклараций намерений. Именно поэтому я и сказал что минимум и тривиального, там я сам статический анализатор. И наверное когда альтернативой упование на конкретику оптимизаций как у того типа, что например обращений в стэк в процессе того трюка не будет (кто это обещал?) - ну, знаете...
4) И да, некоторые плюсовики - реально крутые господа. Именно некоторые. По моим наблюдениям, те которые из си и асма заппгрейдились. Но сериал.бегинщики им все же нагадили, смешав карты. И крутизна плюсов не помогает ардуине раскрыть потенциал атмег. Почему-то. А сишники и для аттиней с 2 кило флеша на все почему-то могут что-то осмысленное.
5) Да, у си есть дурацкие моменты. Но если посмотреть список правил мисры, можно заметить что у плюсов проблем не только есть - но и гораздо больше. И это работает по технологии одно лечим, другое калечим.
6) И таки я ну вот вообще совсем не уверен что желающие прогать на асме оценят плюсы.
7) У плюсов есть фирменный минус: код не реюзабелен. Именно плюсатый код невозможно оформить в нормальную либу и юзать из программ на си, или других ЯП. С другой стороны, сишный код можно довольно много куда прикручивать. У плюсов слишком крутые абстракции для этого. Конечно c GPIO это не такая уж и проблема, но вообще led7_out(digit) я могу запилить и для какого-нибудь Linux в допущении что на платформе GPIO есть и в принципе это может быть довольно абстрактный вызов, ничего не знающий о железе, платформе и реализации.

Ах да, минимальный стартап на си может быть и типа такого, что под кат прятать не обязательно:

Код: Выделить всё

    len = (size_t) &__bss_end;
    len = len - (size_t) &__bss_start;
    memset(&__bss_start, 0, len);

    len = (size_t) &__data_end;
    len = len - (size_t) &__data_start;
    memcpy(&__data_start, &__text_end, len);

    board_init();
p.s. переменная чтобы статические анализаторы не воняли про математику над разными указателями (они правы, плохо, но в стартапе - надо). Реально gcc делает идентичный код и RAM на переменную не жрет. И ноль ассемблера - SP cortex M сам из vectors[0] возьмет. Вон те функции, кстати, можно и самому по минимуму написать, тогда кода совсем мизер. Да, с таким стартапом могут быть некоторые оговорки. Но так можно - и таки на самом си. Хочу посмотреть как плюсовики из именно плюсатого кода поднимут свою механику с конструкторами-деструкторами. А такой номер вообще возможен? То что ассемблерщики всегда могут и это и что угодно иное - кто бы сомневался, они всегда могут все что платформа технически может :)

p.p.s а с вьюжлстудии все знакомые сишники давно свалили на gcc и clang - потому что компилятор си в ней - никакой. Gcc на левую декларацию функции без прототипа бухтит варнингом.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

[uquote="iddqd",url="/forum/viewtopic.php?p=3937307#p3937307"]1) Я не понимаю что люди делают с GCC и Си, чтобы "такой код" не генерился.[/uquote]Ну ведь это же легко, используя вашу reg32_write(reg, val), сделать 10 импульсов на PA9 как в моём примере? Компилируете, показываете такой же код и расходимся.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937307#p3937307"]Ах да, минимальный стартап на си может быть и типа такого,[/uquote]А на С++ он не может быть типа такого?

[uquote="iddqd",url="/forum/viewtopic.php?p=3937307#p3937307"]Хочу посмотреть как плюсовики из именно плюсатого кода поднимут свою механику с конструкторами-деструкторами.[/uquote]Я же чуть выше выложил стартап. Все конструкторы вызываются двумя строками кода, повторю их тут.

Код: Выделить всё

for(void(**fConstr)() = __preinit_array_start; fConstr < __preinit_array_end; (*fConstr++)());
for(void(**fConstr)() = __init_array_start;    fConstr < __init_array_end;    (*fConstr++)());
Причём, как заметил Reflector, они же и для Си нужны, по хорошему.
iddqd
Нашел транзистор. Понюхал.
Сообщения: 156
Зарегистрирован: Вс сен 06, 2020 16:06:10

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение iddqd »

Если вы настаиваете, ок, быренько слепил из того что под рукой, и вышло как-то так:

Код: Выделить всё

    LED1_ON;
 8000eec:	2310      	movs	r3, #16
 8000eee:	4a0a      	ldr	r2, [pc, #40]	; (8000f18 <reset_handler+0x748>)
 8000ef0:	6013      	str	r3, [r2, #0]
    LED1_OFF;
 8000ef2:	603b      	str	r3, [r7, #0]
    LED1_ON;
 8000ef4:	6013      	str	r3, [r2, #0]
    LED1_OFF;
 8000ef6:	603b      	str	r3, [r7, #0]
    LED1_ON;
 8000ef8:	6013      	str	r3, [r2, #0]
    LED1_OFF;
 8000efa:	603b      	str	r3, [r7, #0]
    LED1_ON;
 8000efc:	6013      	str	r3, [r2, #0]
    LED1_OFF;
 8000efe:	603b      	str	r3, [r7, #0]
    LED1_ON;
.... 
Ну да, я 10 раз скопипастил on + off, это для светодиода было, если кто будет настаивать то на сях можно и макрос повтора сделать. Да, более костыльно, но от "стены кода" из копипасты избавит.

А внутрях как раз вот так было:

Код: Выделить всё

#define LED1_ON         REG32_WRITE(GPIOA_BSRR, BIT(LED_PIN1))
#define LED1_OFF        REG32_WRITE(GPIOA_BRR,  BIT(LED_PIN1))
И между нами, LED1_ON как-то информативнее, чтоли, чем какое-то PC15::set которое вообще ни о чем не говорит. Так что сказ про крутой и читаемый код на плюсах, конечно, здорово, но... а вон то и правда менее читаемо вышло? Или более жирно по коду? Не? Тогда какого дьявола, господа?
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

iddqd, а теперь то же самое на контроллере без BRR?

Э!!! А загрузку R7 куда дели?

Добавлено after 21 minute 49 seconds:
[uquote="iddqd",url="/forum/viewtopic.php?p=3937735#p3937735"]И между нами, LED1_ON как-то информативнее, чтоли, чем какое-то PC15::set которое вообще ни о чем не говорит.[/uquote]

Код: Выделить всё

using LED1 = PC15;
[uquote="iddqd",url="/forum/viewtopic.php?p=3937735#p3937735"]Так что сказ про крутой и читаемый код на плюсах, конечно, здорово, но... а вон то и правда менее читаемо вышло?[/uquote]Ну вообще да. 20 строк копипасты вместо указания повторить код 10 раз.
[uquote="iddqd",url="/forum/viewtopic.php?p=3937735#p3937735"]Или более жирно по коду?[/uquote]И это тоже да. На одну команду загрузки адреса в РОН больше. Да и лишний РОН.

Добавлено after 12 minutes 54 seconds:
Кстати, в моём примере вовсе не LED был. Какой смысл дергать его с частотой десяток МГц? Даже объявление LED на плюсах гораздо удобнее.

Код: Выделить всё

using LED1 = TLed<PC13>; // Анод на контроллер
using LED2 = TLed<PC14, false>; // Катод на контроллер
И далее по коду методы On и Off будут бесплатно учитывать схему подключения. А ещё методы Toggle и ReadState. И при этом ему, по большому счёту, всё равно на STM32 он или вообще не на ARM вовсе.
iddqd
Нашел транзистор. Понюхал.
Сообщения: 156
Зарегистрирован: Вс сен 06, 2020 16:06:10

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение iddqd »

[uquote="VladislavS",url="/forum/viewtopic.php?p=3937740#p3937740"]iddqd, а теперь то же самое на контроллере без BRR?[/uquote]Ок, #define LED1_OFF REG32_WRITE(GPIOA_BSRR, BIT(LED_PIN1+16)). И получаем:

Код: Выделить всё

   LED1_ON;
 8000f04:	2110      	movs	r1, #16
    LED1_OFF;
 8000f06:	f44f 1280 	mov.w	r2, #1048576	; 0x100000
    LED1_ON;
 8000f0a:	4b0a      	ldr	r3, [pc, #40]	; (8000f34 <reset_handler+0x764>)
 8000f0c:	6019      	str	r1, [r3, #0]
    LED1_OFF;
 8000f0e:	601a      	str	r2, [r3, #0]
    LED1_ON;
 8000f10:	6019      	str	r1, [r3, #0]
    LED1_OFF;
 8000f12:	601a      	str	r2, [r3, #0]
... 
Э!!! А загрузку R7 куда дели?
Что я про глобальные оптимизации грил? Я пихнул это в проект под рукой, GCC+LTO реюзул r7 внаглую, раз он подходит. А вот на чистом асме так сумничать будет нелегко. Заодно showcase глобальной оптимизации попался.
Ну вообще да. 20 строк копипасты вместо указания повторить код 10 раз.
Так больше соответствует фактическому коду и его активности. Размер кода очевиднее. И если он не нравится, тогда, очевидно, надо пересмотреть подход и возможно циклом оформить, профукав скорость в пользу размера. А у вас что это unroll - на глаз не схватывается. И ощущение сгенеренного кода и эффективности пролюбливается. Оно так и мег кода воткнет, никто и не заметит, пока флеха не кончится.
И это тоже да. На одну команду загрузки адреса в РОН больше. Да и лишний РОН.
Не вы там возмущались что r7 непонятно откуда? В случае GCC+LTO оценка локального кода - не совсем полная картина мира. И как это глобально на оптимизации скажется - более интересный вопрос на самом деле.

А как насчет чуть хитрее? Что если мы хотим дергать сразу 1, 3, 5 и 7 пины порта, одновременно? В моем случае компилер скорее всего 1 константу поменяет. А у вас абстракция такой финт вообще позволит? И если да, что в коде будет? Мне в отличие от моего примера, где я с 90% вероятности угадаю что компилер выдаст - не очевидно вообще совсем нихрена.
Кстати, в моём примере вовсе не LED был. Какой смысл дергать его с частотой десяток МГц?
Он виноват только тем что под руку попался и был подходящим тестовым кроликом.
Даже объявление LED на плюсах гораздо удобнее.

Код: Выделить всё

using LED1 = TLed<PC13>; // Анод на контроллер[/quote] Зато я могу быстро заредефайнить LED1_ON так, что оно прокатит даже, блин, на моем десктопе, для вон того нумлока на клавиатуре (под линуксом). Ну да, код поменяется и будет сильно менее эффективным, но в конце концов - тоже LED и тоже ON. Хоть там и нет никакого port C и вообще, файловая система и файловые операции, в сторону usb-шной клавиатуры. А понятие LED1_ON все же применимо.

[quote]И далее по коду методы On и Off будут бесплатно учитывать схему подключения. А ещё методы Toggle и ReadState. И при этом ему, по большому счёту, всё равно на STM32 он или вообще не на ARM вовсе.[/quote] Ну, хорошо, и что такое PC13 в контексте моего пиюка с usb-клавиатурой и LED num lock'а на ней как LED1? Вот что такое LED1_ON - я могу в два счета оформить и для этой конфиги, хоть конечно за ним и будет вообще совсем другой код в случае писюка (или одноплатника) с Linux.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение Reflector »

[uquote="iddqd",url="/forum/viewtopic.php?p=3937735#p3937735"]

Код: Выделить всё

#define LED1_ON         REG32_WRITE(GPIOA_BSRR, BIT(LED_PIN1))
#define LED1_OFF        REG32_WRITE(GPIOA_BRR,  BIT(LED_PIN1))
И между нами, LED1_ON как-то информативнее, чтоли, чем какое-то PC15::set которое вообще ни о чем не говорит.[/uquote]
LED1_ON/LED1_OFF/LED_PIN1 сначала нужно задефайнить, для каждого светодиода. А будут разные порты, то может добавиться LED_PORT, или нужен LED1_TOGGLE - будь добр добавь и его. Чтобы появились пины со всеми своими методами нужно лишь добавить хедер, а дальше будет максимум одно переопределение имени на диод.
А как насчет чуть хитрее? Что если мы хотим дергать сразу 1, 3, 5 и 7 пины порта, одновременно? В моем случае компилер скорее всего 1 константу поменяет. А у вас абстракция такой финт вообще позволит? И если да, что в коде будет?

Код: Выделить всё

PinList<PC7, PC3, PC5, PC1>::write(0b1010);

// ldr r2, [pc, #220]
// ldr r6, [pc, #224]
// str r6, [r2, #24]
Добавлено after 27 minutes 25 seconds:
[uquote="iddqd",url="/forum/viewtopic.php?p=3937775#p3937775"]Ну, хорошо, и что такое PC13 в контексте моего пиюка с usb-клавиатурой и LED num lock'а на ней как LED1? Вот что такое LED1_ON - я могу в два счета оформить и для этой конфиги, хоть конечно за ним и будет вообще совсем другой код в случае писюка (или одноплатника) с Linux.[/uquote]
Помнится кто-то ранее в этой теме говорил, что даже F4 - это слишком жирно и потому ему не нужно, а писюк или одноплатник на линуксе значит не жирно? :) Какое это имеет отношение к эмбедду?
Последний раз редактировалось Reflector Пн дек 07, 2020 11:41:14, всего редактировалось 1 раз.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

[uquote="iddqd",url="/forum/viewtopic.php?p=3937775#p3937775"]Ок, #define LED1_OFF REG32_WRITE(GPIOA_BSRR, BIT(LED_PIN1+16)). И получаем:

Код: Выделить всё

   LED1_ON;
 8000f04:	2110      	movs	r1, #16
    LED1_OFF;
 8000f06:	f44f 1280 	mov.w	r2, #1048576	; 0x100000
    LED1_ON;
 8000f0a:	4b0a      	ldr	r3, [pc, #40]	; (8000f34 <reset_handler+0x764>)
... 
[/uquote]И получаем дополнительную ЖИРНУЮ команду загрузки константы, как ни крути.

Добавлено after 10 minutes 40 seconds:
[uquote="iddqd",url="/forum/viewtopic.php?p=3937775#p3937775"]А как насчет чуть хитрее? Что если мы хотим дергать сразу 1, 3, 5 и 7 пины порта, одновременно? В моем случае компилер скорее всего 1 константу поменяет. А у вас абстракция такой финт вообще позволит? И если да, что в коде будет?[/uquote]

Код: Выделить всё

//using PINS = PinList<PC7, PC5, PC3, PC1>;
//Repeat<10>([]{ PINS::set(); PINS::clear(); } );
        MOVS     R0,#+170
        LDR.N    R1,??DataTable1_4  ;; 0x48000818
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
        STR      R0,[R1, #+0]
        STRH     R0,[R1, #+2]
А если на разных портах, ась?

[uquote="iddqd",url="/forum/viewtopic.php?p=3937775#p3937775"]Мне в отличие от моего примера, где я с 90% вероятности угадаю что компилер выдаст - не очевидно вообще совсем нихрена.[/uquote]Мне очевидно. Очевидно, что для Reflector тоже очевидно. А то что вам неочевидно, так ваши проблемы.
iddqd
Нашел транзистор. Понюхал.
Сообщения: 156
Зарегистрирован: Вс сен 06, 2020 16:06:10

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение iddqd »

Насколько я понимаю глобальный оптимизатор - так в том случае если ранее похожего не попадалось. Да, "без BSRR" является достаточно уникальной конструкцией, потому что слеплено специально для того теста. Однако если такого будет несколько, вероятно и реюз константы случится. Ну и кроме того сетап дергов случается до их начала - так что на скорость не влияет. Ну и без BSRR как я помню F0, чтоли. У них еще и набор команд - v6, он в целом похуже чем m3, на этом еще дополнительный слив бывает особенно в математике всякой.

А вот как в тех концепциях сразу несколько пинов с эффективным кодом - я не совсем догоняю. Я в вон тех терминах в принципе я могу описать манипуляцию сразу набором пинов, и на set, и на reset, и будет не сильно хуже по коду. Просто константа станет другой. А в ваших мегаконцепциях чего будет?
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение Reflector »

[uquote="iddqd",url="/forum/viewtopic.php?p=3937803#p3937803"]А вот как в тех концепциях сразу несколько пинов с эффективным кодом - я не совсем догоняю.[/uquote]
Может это поможет что-то прояснить.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

[uquote="iddqd",url="/forum/viewtopic.php?p=3937803#p3937803"]Насколько я понимаю глобальный оптимизатор[/uquote]А теперь вставь этот код в прерывание, допустим, где содержимое регистров за тебя никто раньше не загрузил. А примени в другой единице трансляции, а... Да много ли ещё чего бывает. Компилятор не устаёт.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937803#p3937803"]А вот как в тех концепциях сразу несколько пинов с эффективным кодом - я не совсем догоняю.[/uquote]Не догоняю, но осуждаю. Тоже знакомо.

[uquote="iddqd",url="/forum/viewtopic.php?p=3937803#p3937803"]Просто константа станет другой. А в ваших мегаконцепциях чего будет?[/uquote]Я же показал что будет. Указываем список пинов и погнали. Причем, пины могут быть из разных портов в любой последовательности. Всё сгруппируется как надо. Это могут быть не только set или reset, а write, read, toggle.

Я даже не буду просить повторить нижеследующий пример. Берём две группы пинов на разных портах. Читаем одну группу как байт, инвертируем и записываем во вторую группу.

Код: Выделить всё

PinList<PC7, PC6, PC5, PC4, PC3, PA0, PA1, PA5> pins1;
PinList<PB1, PB2, PB3, PB4, PB5, PD5, PD1, PD0> pins2;

pins2 = ~pins1;
Сколько вы это будете руками ковырять... Компилятор делает за долю секунды.
Спойлер

Код: Выделить всё

//pins2 = ~pins1;
        LDR.N    R1,??DataTable1_4  ;; 0x48000010
        LDR      R2,[R1, #+2048]
        LDR      R3,[R1, #+0]
        AND      R3,R3,#0x23
        AND      R2,R2,#0xF8
        ORR      R2,R2,R3, LSR #+5
        AND      R0,R3,#0x2
        LSLS     R3,R3,#+2
        ORRS     R2,R0,R2
        AND      R3,R3,#0x4
        ORRS     R2,R3,R2
        MVNS     R2,R2
        AND      R3,R2,#0xF8
        RBIT     R0,R3
        LSRS     R0,R0,#+23
        AND      R0,R0,#0x3E
        ORR      R0,R0,#0x3E0000
        STR      R0,[R1, #+1032]
        AND      R0,R2,#0x3
        LSLS     R2,R2,#+3
        AND      R2,R2,#0x20
        ORRS     R2,R2,R0
        ORR      R2,R2,#0x230000
        STR      R2,[R1, #+3080]
[uquote="iddqd",url="/forum/viewtopic.php?p=3937803#p3937803"]Ну и без BSRR как я помню F0, чтоли.[/uquote]Только без BRR. В F4 или H7, например. Мэинстрим, как ни крути, приходится учитывать.
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение AVI-crak »

Как вам такая запись?

Код: Выделить всё

gpio_one_pin(zap_gpio.H.pin05.v_af12_fmc_sdnwe.speed4.pull_up.lock_on); /// FMC_sdnwe
Здесь структура - как символьный путь заполнения параметров. Если не всем видно - основной упор на AF функции контактов, они всегда уникальные. Своя уникальная огромная структура для каждого мк в уникальном корпусе. Потому как даже в одной серии могут быть незначительные различия в назначении ног. Ну есно структура заполняется не руками, но подбрасывать уголь в топку приходится, что немного утомительно.
Если кому нужно под другой мк - могу сделать.
https://github.com/AVI-crak/gpio_one
FFFF
Родился
Сообщения: 8
Зарегистрирован: Пн дек 07, 2020 14:44:59

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение FFFF »

основное достоинство ассемблера это предсказуемый результат, вы получаете РОВНО ТО что написали, это надо четко понимать. все остальное это костыли которые призваны облегчить труд программиста (а равно и вхождение) и заработать бизнесу на нем
синергия возможна лишь когда программист владеет и ассемблером и костылем в равной мере на высоком уровне, в противном случае одного знания костыля недостаточно чтобы писать хороший код
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение Reflector »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=3937846#p3937846"]Как вам такая запись?[/uquote]
Инициализация десятка пинов с -O0 у меня 23КБ отожрала, потому что самая тяжелая функция принудительно инлайнится :) Если этот инлайн убрать, то в разы вырастает размер с включенной оптимизацией.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

AVI-crak, как для одной ноги вполне нормально получается, если закрыт глаза на попранные стандарты.
Спойлер

Код: Выделить всё

Disassembly of section .text.zap_gpio_one_pin.constprop.0:

00000000 <zap_gpio_one_pin.constprop.0>:
    zap_in_TypeDef init;
    init.data_s = s_gpio;
    zap_GPIO_TypeDef* GPIOx = (zap_GPIO_TypeDef*)(0x40020000 + (uint32_t)init.port);


    GPIOx->MODER = (GPIOx->MODER & (~(3 << (init.pin << 1)))) | (init.mode << (init.pin << 1));
   0:	4b16      	ldr	r3, [pc, #88]	; (5c <zap_gpio_one_pin.constprop.0+0x5c>)
static void zap_gpio_one_pin (const uint32_t s_gpio)
   2:	b570      	push	{r4, r5, r6, lr}
    GPIOx->MODER = (GPIOx->MODER & (~(3 << (init.pin << 1)))) | (init.mode << (init.pin << 1));
   4:	2405      	movs	r4, #5
   6:	681e      	ldr	r6, [r3, #0]
   8:	0060      	lsls	r0, r4, #1
   a:	2203      	movs	r2, #3
   c:	fa02 f500 	lsl.w	r5, r2, r0
  10:	2102      	movs	r1, #2
  12:	ea26 0605 	bic.w	r6, r6, r5
  16:	4081      	lsls	r1, r0
  18:	4331      	orrs	r1, r6
  1a:	6019      	str	r1, [r3, #0]
    GPIOx->PUPDR = (GPIOx->PUPDR & (~(3 << (init.pin << 1)))) | (init.pup << (init.pin << 1));
  1c:	68de      	ldr	r6, [r3, #12]
  1e:	2101      	movs	r1, #1
  20:	4081      	lsls	r1, r0
  22:	ea26 0605 	bic.w	r6, r6, r5
  26:	4331      	orrs	r1, r6
  28:	60d9      	str	r1, [r3, #12]
    GPIOx->OSPEEDR = (GPIOx->OSPEEDR & (~(3 << (init.pin << 1)))) | (init.sped << (init.pin << 1));
  2a:	6899      	ldr	r1, [r3, #8]
  2c:	462a      	mov	r2, r5
  2e:	ea21 0105 	bic.w	r1, r1, r5
  32:	430a      	orrs	r2, r1
  34:	609a      	str	r2, [r3, #8]
    if (init.yper)  GPIOx->OTYPER |= 1 << init.pin; else GPIOx->OTYPER &= ~(1 << init.pin);
  36:	6859      	ldr	r1, [r3, #4]
  38:	2201      	movs	r2, #1
  3a:	40a2      	lsls	r2, r4
  3c:	ea21 0102 	bic.w	r1, r1, r2
  40:	6059      	str	r1, [r3, #4]
    if (init.mode == 2 )
    {
        GPIOx->AFR[init.pin_afa] = (GPIOx->AFR[init.pin_afa] &(~(15 << (init.pin_afd << 2)))) | (init.af << (init.pin_afd << 2));
  42:	6a19      	ldr	r1, [r3, #32]
  44:	f421 0170 	bic.w	r1, r1, #15728640	; 0xf00000
  48:	f441 0140 	orr.w	r1, r1, #12582912	; 0xc00000
  4c:	6219      	str	r1, [r3, #32]
    };
    if (init.lok)
    {
        GPIOx->LCKR = (1 << 16) | (1 << init.pin);
  4e:	f442 3180 	orr.w	r1, r2, #65536	; 0x10000
  52:	61d9      	str	r1, [r3, #28]
        GPIOx->LCKR = 1 << init.pin;
  54:	61da      	str	r2, [r3, #28]
        GPIOx->LCKR = (1 << 16) | (1 << init.pin);
  56:	61d9      	str	r1, [r3, #28]
    };
};
  58:	bd70      	pop	{r4, r5, r6, pc}
  5a:	bf00      	nop
  5c:	40021c00 	.word	0x40021c00
Плюсовой класс байт 20 выиграл. Но когда это на 20-100 ног умножится, то за гранью добра и зла получится. И во всех режимах все регистры задаются, что не всегда необходимо. Но тут С выше головы не прыгнет.

Добавлено after 53 seconds:
[uquote="Reflector",url="/forum/viewtopic.php?p=3937925#p3937925"]Инициализация десятка пинов с -O0 у меня 23КБ отожрала,[/uquote]Что такое -O0 ??? :)))
Ответить

Вернуться в «ARM»