Ассемблерные вставки

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Прорезались зубы
Сообщения: 210
Зарегистрирован: Пн окт 21, 2013 07:33:45

Сообщение FPGAlover »

И еще раз здравствуйте! Вот и добрался я до своего любимого ассемблера :-)
Интересует технический вопрос: Как это делается ?
можно ли непосредственно в сишный код вставлять? если можно то как?
если нельзя то как это оформить?
В конце концов, посодействуйте авторитетной ссылочкой :-)
Шоб я польку танцевал..
Реклама
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

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

void
_delay_loop_1(uint8_t __count)
{
	__asm__ volatile (
		"1: dec %0" "\n\t"
		"brne 1b"
		: "=r" (__count)
		: "0" (__count)
	);
}
Упс, не ту сцылку прицепил, но смысл такой же. Вот для ARM: http://www.ethernut.de/en/documents/arm-inline-asm.html
Последний раз редактировалось coredumped Чт дек 12, 2013 23:12:41, всего редактировалось 1 раз.
Все будет только лучше, в крайнем случае - хуже.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Сообщение dosikus »

FPGAlover писал(а):И еще раз здравствуйте! Вот и добрался я до своего любимого ассемблера :-)
Так вот откуда ноги растут ... :)))
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1433
Зарегистрирован: Вс дек 02, 2012 03:13:48
Откуда: Калининград

Сообщение balmer »

Использую GCC, и там собственно говоря никаких особенностей нет и ничем не отличается кроме команд от AVR и x86.
Набираешь в поисковике "gcc arm assembly" или "gcc STM32 assembly" и радуешься.

Только ASM редко нужен. Память, как на дешевых AVR смысла нет экономить. Time Critical места встречаются очень редко. Да и для большинства Time Critical есть своя периферия.
Реклама
Эиком - электронные компоненты и радиодетали
Прорезались зубы
Сообщения: 210
Зарегистрирован: Пн окт 21, 2013 07:33:45

Сообщение FPGAlover »

coredumped, спасибо! с первого взгляда возникла мысль: "что это за ахинея?? как то это рвет шаблон...", но пройдя по ссылке все приобрело смысл :-)
balmer писал(а):Память, как на дешевых AVR смысла нет экономить
ну это понятно. Больше быстродействие интересует.
глянул, какой код генерит компилятор и присел :-)
на 120мгц опрос внешнего ацп с занесением в буфер работает с частотой 3 Мгц. То есть 40тактов на цикл... и это хваленый риск :-)

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

 for (j=0;j<256;j++) {
   GPIOB->BSRRL |= 1<<12; 
   for (i=0;i<1;i++){};
   buff[j] = GPIOB->ODR;
   GPIOB->BSRRH |= 1<<12;
 }
дизасмом посмотрел что творит компилятор.. не сказать что офигел, но был немного разочарован...
Кстати, вопрос в продолжение: я, конечно, слабо себе представляю архитектуру АРМа. Но догадываюсь что шина не позволяет за такт произвести операцию чтения и записи в память (например инкремент ячейки памяти). Я прав?
Шоб я польку танцевал..
Реклама
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1433
Зарегистрирован: Вс дек 02, 2012 03:13:48
Откуда: Калининград

Сообщение balmer »

Ну операция | тут совсем лишняя.

А вот такой код

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

  for (int j=0;j<256;j++)
  {
   GPIOB->BSRR = 1<<12; 
   for (int i=0;i<1;i++){};
   buff[j] = GPIOB->ODR;
   GPIOB->BRR = 1<<12;
  }
компилируется в

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

  79 0020 4FF48051 		mov	r1, #4096
  80 0024 074A     		ldr	r2, .L9
  82 0026 0848     		ldr	r0, .L9+4
  85 0028 30B5     		push	{r4, r5, lr}
  92 002a 0023     		movs	r3, #0
  95 002c 0D46     		mov	r5, r1
  97              	.L7:
  98 002e 9561     		str	r5, [r2, #24]
 101 0030 948A     		ldrh	r4, [r2, #20]
 102 0032 E4B2     		uxtb	r4, r4
 103 0034 C454     		strb	r4, [r0, r3]
 105 0036 0133     		adds	r3, r3, #1
 107 0038 B3F5807F 		cmp	r3, #256
 109 003c 1185     		strh	r1, [r2, #40]	@ movhi
 111 003e F6D1     		bne	.L7
По мне так вполне прилично.
Естественно for (int i=0;i<1;i++){}; выкинуто полностью, ибо оптимизатор видит что цикл нафиг не нужен.

Хотя да, ногодрыг - это одно из мест, где имело бы смысл на ASM точную задержку выставить. Правда мне такой подход не нравится. Меняешь частоту процессора - будь добр переписать код, неее я уж какнить DMA с Таймерами настрою на этот случай, будет надежнее.
Реклама
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

Скажем, DMA с внешним "параллельным" АЦП связать не просто - единственный вариант FSMC (поправьте меня, если я не прав). Да и смысла особого нет, при передаче 1 слова за итерацию. Тут бы проектик целиком увидеть. Таймер - да, нужная вещь, но с прерываниями надо быть внимательным - посмотрите какой код генерирует компилятор при входе - выходе из ISR. Если период таймера небольшой, то использование таймера может стать неэффективным, если нужно выжать из процессора все ресурсы.
Что касается вставки ассемблерного кода и кода, генерируемого компилятором. Нужно было мне забирать данные с FPGA, порядка 10 Мбайт в секунду, блоками по 1К, обрабатывать и отправлять в эзернет. FSMC применить не получалось, ввиду не совсем удачного распределения GPIO. В общем - ногодрыг, задержки __nop() итп. Думал написать процедуру на ассемблере, чтоб выжать из процессора все, а когда посмотрел листинг компиллятора, понял, что лучшше я не сделаю пожалуй. Я это к тому, что компиляторы С довольно умные стали, главное код правильно написать. А методов оптимизации море - раскручивание циклов, работа с указателями с учетом архитектуры итп. Лучший оптимизатор - моск :)
Все будет только лучше, в крайнем случае - хуже.
Друг Кота
Аватара пользователя
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Сообщение dosikus »

coredumped писал(а):Скажем, DMA с внешним "параллельным" АЦП связать не просто - единственный вариант FSMC (поправьте меня, если я не прав).
Конечно не прав. GPIO та же периферия . Конечно при работе с DMA много не выжмешь , зато будет аппаратно...

А вот почему буфер читается с ODR а не с IDR так же не понятно

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

 buff[j] = GPIOB->ODR;
Прорезались зубы
Сообщения: 210
Зарегистрирован: Пн окт 21, 2013 07:33:45

Сообщение FPGAlover »

dosikus писал(а):А вот почему буфер читается с ODR а не с IDR так же не понятно
Предельно понятно :)) - описка...

С ДМА я практически не разбирался(особенно с генерацией запросов)
Поэтому не представляю, каким образом это на ДМА вообще можно сделать?
2 канала запускать? : 1 на клок (тут можно еще и управление усилителем запихать :-)) и 1 на данные)? А синхронизировать разными фронтами одного события?
Так возможно?

В идеале, конечно, надо плис подпаивать и хоть 200 МГц цифруй по четырем каналам параллельно :-)
Шоб я польку танцевал..
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

dosikus писал(а):Конечно не прав. GPIO та же периферия . Конечно при работе с DMA много не выжмешь , зато будет аппаратно...
Ну да, ну да... А строб данных как сформировать (шина данных 16-битная)? Варианты?

2 FPGAlover: В Вашем случае с DMA выигрыш не получить - передача 1 байта(слова).
В моем - да, было бы хорошо, если бы можно было сформировать клок на FPGA + еще несколько сигналов. Использовать втрой канал ПДП - не вариант при пакетной передаче с подтверждением. FSMC - да, но платы уже готовы, а в 100-ногом корпусе расположение пинов таково(+ еще Ethernet, I2C), что нет вариантов замапить. Одеяльце коротковато :))
В связке с ПЛИС можно поиграться с FIFO на ПЛИС + FSMC на ARM. Тут DMA очень даже выручит. Перекладываете работу с АЦП на стейтмашину, данные в FIFO, а дальше уж - куда Вам их надо :) По ходу можно еще фильтрануть, если надо - пики/выбросы отсеять, огибающую посчитать - да что угодно!
Все будет только лучше, в крайнем случае - хуже.
Прорезались зубы
Сообщения: 210
Зарегистрирован: Пн окт 21, 2013 07:33:45

Сообщение FPGAlover »

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

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

 uint16_t buff[256]; 
 uint32_t i = 0;
 uint32_t*  SetReg   ; 
 uint32_t*  ResetReg ;
 uint32_t*  DataReg ;
 SetReg    = (uint32_t*)&GPIOB->BSRRL;
 ResetReg  = (uint32_t*)&GPIOB->BSRRH;
 DataReg   = (uint32_t*)&GPIOB->IDR;
 while(1){
 uint32_t j=0;
 do {
   *SetReg = 1<<12; //set   bit
   i=0;                      //пауза.. АЦП быстродействующее, вполне хватает 
   buff[j++] = *DataReg;
   *ResetReg = 1<<12; //set   bit
 } while (j<256);
2 coredumped: На самом деле, в моем случае отношение времени сбора и обработки информации весьма мало. т.е. Мне важно с хорошей частотой собрать в буфер, а потом хоть по усарту выкачивать :music:
Последний раз редактировалось FPGAlover Пт дек 13, 2013 11:05:28, всего редактировалось 1 раз.
Шоб я польку танцевал..
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

Попробуй такой вариант:

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

uint16_t buff[256]; 
 uint32_t i = 0;
 uint32_t*  SetReg   ; 
 uint32_t*  ResetReg ;
 uint32_t*  DataReg ;
 uint16_t *bp; 
 bp = buff;
 SetReg    = (uint32_t*)&GPIOB->BSRRL;
 ResetReg  = (uint32_t*)&GPIOB->BSRRH;
 DataReg   = (uint32_t*)&GPIOB->ODR;

 while(1){
 uint32_t j=256;

*SetReg = 1<<12; //set   bit
 do {
   *(bp++) = *DataReg;
   *ResetReg = 1<<12; //set   bit
   *SetReg = 1<<12; //set   bit
 } while (j--);
Последний раз редактировалось coredumped Пт дек 13, 2013 11:06:56, всего редактировалось 1 раз.
Все будет только лучше, в крайнем случае - хуже.
Друг Кота
Аватара пользователя
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Сообщение dosikus »

coredumped писал(а): Ну да, ну да... А строб данных как сформировать (шина данных 16-битная)? Варианты?
Тем же DMA , посмотри на казусе мою реализацию с LED дисплеем .
С таймера пинать 2 канала DMA, один на строб второй на захват с IDR .
Прорезались зубы
Сообщения: 210
Зарегистрирован: Пн окт 21, 2013 07:33:45

Сообщение FPGAlover »

coredumped писал(а):Попробуй такой вариант:
почему то в хардфаулт уходит...
Сейчас выясним.
Выяснил : bp = buff; перед главным циклом стоит :-)
Выигрыша в скорости на глаз не видно.

и кстати, я в си не силен, но... компиляторы отродясь такое понимали?
bp = buff;
это выглядил логичнее, но компилятор не понимает:
bp = &buff;
а с этим все в порядке...
bp = &buff[0];

и еще непонятны предпосылки к генерации кода на while(j--):

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

MOVS  R6,R5
SUBS  R5,R6,1
CMP    R6,#0
BNE.N  ??Main_1
в системе команд отсутствует декремент регистра и флаг "зеро"?
Шоб я польку танцевал..
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

А компайлер какой?
Вариант bp = buff; и bp = &buff[0]; одно и то же.
Команды декремента нет, есть SUBS - который должен влиять на флаг Z (Z флаг имеется), не понятно зачем компилятор всунул CMP :o
Я Кейлом пользуюсь, у меня все норм.
Мой вариант должен работать чуть быстрее, хотя очень сильно зависит от компилятора. Посмотри ассемблерные листинги и сравни.
Все будет только лучше, в крайнем случае - хуже.
Прорезались зубы
Сообщения: 210
Зарегистрирован: Пн окт 21, 2013 07:33:45

Сообщение FPGAlover »

coredumped писал(а):А компайлер какой?
пользую IAR 6.5

листинги не сходятся ну вообще...
У меня цикл с I стоически генерит код, несмотря на полную оптимизацию.
а если честно, как то ваш листинг, в моем нубском мозгу(смысл половины команд пока непонятен), слабо коррелируется с исходником... Какие то непонятные L9 и push. а где же pop?.

кстати, давно интересовал вопрос:
"4FF48051 mov r1, #4096" откуда берется константа 4096? в "4FF48051" ее ни слухом ни духом :-)
Шоб я польку танцевал..
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1433
Зарегистрирован: Вс дек 02, 2012 03:13:48
Откуда: Калининград

Сообщение balmer »

FPGAlover писал(а): "4FF48051 mov r1, #4096" откуда берется константа 4096?
СпойлерFlexible second operand
Many general data processing instructions have a flexible second operand. This is shown as operand2 in the descriptions of the syntax of each instruction.
Operand2 can be a:
● Constant
● Register with optional shift
Constant
You specify an operand2 constant in the form #constant, where constant can be:
● Any constant that can be produced by shifting an 8-bit value left by any number of bits
within a 32-bit word.
● Any constant of the form 0x00XY00XY
● Any constant of the form 0xXY00XY00
● Any constant of the form 0xXYXYXYXY
In the constants shown above, X and Y are hexadecimal digits.
Это случай by shifting an 8-bit value left by any number of bits
within a 32-bit word.
Прорезались зубы
Сообщения: 210
Зарегистрирован: Пн окт 21, 2013 07:33:45

Сообщение FPGAlover »

Ну ничего себе! архиватор ну уровне расшифровки команд :-)
Шоб я польку танцевал..
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

Это еще 16-битный набор команд thumb - слегка "урезанный". Посмотрите что можно в режиме ARM (32-битном) http://www.gaw.ru/html.cgi/txt/doc/micr ... g_data.htm
Правда в Cortex-M (к которым пренадлежит семейство stm32) набор ARM отсутствует, только THUMB
Все будет только лучше, в крайнем случае - хуже.
Ответить

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