Как стать автором
Обновить

Комментарии 16

Посидел сейчас, и получил размер программы 56 байт… меньше уже не знаю как сделать — мешает формат THUMB инструкций (требуется выравнивание к 4 байтам — и программа слишком маленькая чтобы было что менять) :-)

p.s. осталось только проверить на работоспособность (но это только дома)
гм… 52 байта…
ну и совсем неожиданные 44 байта, но этот вариант точно нужно проверить «на железе»…
написал на gcc за 10 минут тоже самое и сразу влезло в 52 байта
Program Size:
      text	   data	    bss	    dec	    hex	filename
        52	      0	  65536	  65588	  10034	Gate_Tester.elf


версия GNU Tools ARM Embedded 4.6 2012q4
ключи компилирования:
arm-none-eabi-gcc -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -Wall -ffunction-sections -g -Os -c…
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Wl -nostartfiles -g -Wl,-Map=Gate_Tester.map -Os -Wl,--gc-sections -LE:/gsm/src/Gate_Tester -Wl,-TE:/gsm/src/Gate_Tester/arm-gcc-link.ld -g -o Gate_Tester.elf ..\obj\stm32kiss_button.o

оптимизация по размеру -Os, LTO (оптимизация при линковке) нет в этой версии gcc

void min_Reset_Handler();

#define STACK_SIZE       0x00004000      /*!< Stack size (in Words)           */
__attribute__ ((section(".co_stack"))) unsigned long minStack[STACK_SIZE];

__attribute__ ((section(".min_isr_vector"))) void (* const minVectors[])(void) =
{
  (void *)&minStack[STACK_SIZE-1],     /*!< The initial stack pointer*/
  min_Reset_Handler,                   /*!< Reset Handler            */
};

void min_Reset_Handler()
{
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
	GPIOD->MODER |= GPIO_MODER_MODER15_0;

	uint32_t counter;
	volatile uint32_t *led = (*(volatile uint32_t *)(PERIPH_BB_BASE + ((((uint32_t)&GPIOD->ODR) - PERIPH_BASE)*32) + 15*4));

	while (true)
	{
		(*led) = counter >> 31;
		counter += 1024;
	}
}


Disassembly of section .text:

08000000 <minVectors>:
 8000000:	fc ff 00 10 09 00 00 08                             ........

08000008 <min_Reset_Handler>:
 8000008:	4b08      	ldr	r3, [pc, #32]	; (800002c <min_Reset_Handler+0x24>)

;RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
 800000a:	6b19      	ldr	r1, [r3, #48]	; 0x30
 800000c:	f041 0108 	orr.w	r1, r1, #8
 8000010:	6319      	str	r1, [r3, #48]	; 0x30

;GPIOD->MODER |= GPIO_MODER_MODER15_0;
 8000012:	f5a3 5330 	sub.w	r3, r3, #11264	; 0x2c00
 8000016:	6819      	ldr	r1, [r3, #0]
 8000018:	f041 4180 	orr.w	r1, r1, #1073741824	; 0x40000000
 800001c:	6019      	str	r1, [r3, #0]

;volatile uint32_t *led = (*(volatile uint32_t *)(PERIPH_BB_BASE + ((((uint32_t)&GPIOD->ODR) - PERIPH_BASE)*32) + 15*4));
 800001e:	4b04      	ldr	r3, [pc, #16]	; (8000030 <min_Reset_Handler+0x28>)

;uint32_t counter;
 8000020:	681b      	ldr	r3, [r3, #0]

<min_Reset_Handler_while>:
 8000022:	0fd1      	lsrs	r1, r2, #31	; 
 8000024:	6019      	str	r1, [r3, #0]    ; (*led) = counter >> 31;
 8000026:	f502 6280 	add.w	r2, r2, #1024	; counter += 1024;
 800002a:	e7fa      	b.n	8000022 <min_Reset_Handler_while>

 800002c:	40023800 	.word	0x40023800
 8000030:	424182bc 	.word	0x424182bc 

или в сыром виде без моих камментов:
image


ld файл стандартный кокосовский
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/* Internal Memory Map*/
MEMORY
{
	rom (rx)  : ORIGIN = 0x08000000, LENGTH = 0x000F8000
	ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
	ccm (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000
}

_eram = 0x20000000 + 0x00020000;

/* Section Definitions */ 
SECTIONS 
{ 
    .text : 
    { 
	   	. = 0x00000000;
        /*KEEP(*(.isr_vector .isr_vector.*))*/
        KEEP(*(.min_isr_vector .min_isr_vector.*)) 
        *(.text .text.* .gnu.linkonce.t.*) 	      
        *(.glue_7t) *(.glue_7)		                
        *(.rodata .rodata* .gnu.linkonce.r.*)		    	                  
    } > rom
    
    .ARM.extab : 
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > rom
    
    __exidx_start = .;
    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > rom
    __exidx_end = .;
    
    . = ALIGN(4); 
    _etext = .;
    _sidata = .; 
    		
    .data : AT (_etext) 
    { 
        _sdata = .; 
        *(.data .data.*) 
        . = ALIGN(4); 
        _edata = . ;
    } > ram

    /* .bss section which is used for uninitialized data */ 
    .bss (NOLOAD) : 
    { 
        _sbss = . ; 
        *(.bss .bss.*) 
        *(COMMON) 
        . = ALIGN(4); 
        _ebss = . ; 
    } > ram
    
    /* stack section */
    .co_stack (NOLOAD):
    {
        . = ALIGN(8);
        *(.co_stack .co_stack.*)
    } > ccm
       
    . = ALIGN(4); 
    _end = . ; 
} 



бинарник в хекс редакторе:
image
ну на счет 10 минут — что то «меня берут смутные сомнения» (с) Брилиантовая рука, но «ход» со сдвигом- однозначно интересен!!! я до такого простого и краткого решения не додумался…

тогда 38 байт! (только с позицией стека нужно уточнить, но помоему правильно)
Disassembly of section .text:

00000000 <AB_STACK-0x8>:
   0:	00000008 	.word	0x00000008
   4:	00000015 	.word	0x00000015

00000008 <AB_STACK>:
   8:	00000001 	.word	0x00000001
   c:	4247060c 	.word	0x4247060c
  10:	42418038 	.word	0x42418038

00000014 <Reset>:
  14:	bc0e      	pop	{r1, r2, r3}
  16:	6019      	str	r1, [r3, #0]
  18:	6011      	str	r1, [r2, #0]

0000001a <BLINK_LOOP>:
  1a:	0fe1      	lsrs	r1, r4, #31
  1c:	f8c3 1284 	str.w	r1, [r3, #644]	; 0x284
  20:	f504 6480 	add.w	r4, r4, #1024	; 0x400
  24:	e7f9      	b.n	1a <BLINK_LOOP>

Бинарник:
помоему регистр перепутал на запись значения,… дома проверю :-)
браво, но смысла нет кроме рекорда длинны и образовательного смысла для тех кто слаб в асме.
я своим постом хотел сказать что даже на мелких и ничтожно мелких задачах Си в прямых руках по всем параметрам на уровне асма.
А по потреблению времени — реально 10 минут, я дольше ответ оформлял.
ну все примеры смысла не имеют, но для понимания механизма очень полезны!

я вот про сдвиговую генерацию значения даже не додумался!!! более того — со сдвигами у меня туго — сидел и на бумажке рисовал сейчас :-))

в моем примере запись в R2 и в R3 местами поменять нужно!!!

кстати, на асме — на больших участках кода оптимизировать код проще — зачастую 5-10 строк асм-кода уже можно в подпрограммы выделять, да и частичное использование кода проще делать…

хотя конечно на асме тяжело писать — меня например сейчас напрягает то, что не знаю как делать изолированные метки :-(
в armasm метки кроме определенных директивами компилятора export/import видны только внутри файла исходника…
то есть шанса на пересечение в разных файлах нет…
а вот в GNU AS такой фичи не нашел :-((( вернее она там есть (по названию метки, не помню точно с «L» чтоли начинаться должны) — но указано (как я понял) как отмирающая что ли, и не во всех версиях реализована…
" на асме — на больших участках кода оптимизировать код проще" вот только человек с этим справляется хуже т.к. оптимизирует частности и не всегда и не везде, а компилятор всё и сразу, может быть в каких то мелочах похуже человека но в целом картина выглядит существенно более сбалансированной.

Как то надо было адаптировать gprs загрузчик с STM32F4xx на STM32F10x самый младший, при этом он был написан на Си и модульный, отдельно драйвер уарта, отдельно парсер команд, отдельно regexp для парсера, отдельно управлятор АТ командами и тд.
А надо было уменьшить в 2-3 раза размер флеша и озу.
При помощи простых операций не вмешиваясь в суть исходников на Си я это сделал вполне успешно, было потребление озу 24-30кбайт, стало 12кбайт. И вписался в 4к ОЗУ из первоначальных 12к.
А сколько времени займёт переписать на ассемблере около 10 тысяч строк Си кода? и точно результат влезет в 12к флеша? Не профукаем ли мы какие либо мелочи спустя лет десять?

Насчёт глобальных и локальных меток… помню лет 20 назад когда кодил на асме в турбоасме были директивы для этого, помоему это global и import если не ошибаюсь, попробуй поискать аналогичные.
Насчёт глобальных и локальных меток… помню лет 20 назад когда кодил на асме в турбоасме были директивы для этого, помоему это global и import если не ошибаюсь, попробуй поискать аналогичные

нашел, но что то не соображу как теперь cmd файл поправить :-(

нужно в цикле организовать перебор каталогов и файлов в них, потом в этом же цикле создать в отдельном каталоге такую же структуру каталогов (вот тут я что то уже голову сломал как это сделать) и запустить для каждого файла .asm компилятор чтобы он сделал .o файл…
а потом все получившиеся .o файлы подсунуть компановщику…

p.s. у меня пока не получается создать структуру каталогов :-(
а разве этим не makefile или Autotools должен заниматься?
в том же эклипсе (работает на makefile) всё делается автоматом независимо от структуры директорий и не требуя от пользователя никаких действий
makefile же не берется ниоткуда его и нужно написать… :-)

сейчас в принципе уже накидал, тестирую… очень интересная весчЬ получилась!!! наверное ее стоит выделить в публикацию
Посмотрите на waf, он выглядит крайне правильно.
А зачем тут сдвиг, если значение всё равно берётся из младшего бита? Так?

1: str r4,[r3, #644]
adc r4,r4,#2048
b 1b
Запостил а потом подумал.
Имел в виду конечно же ADCS, которого в thumb2 в такой форме нет.

Спасибо, очень интересный цикл статей, на таком уровне последний раз работал только с AVR.
Проверил на STM32F4-Discovery — все отлично работает.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории