Перейти к содержанию
    

Код на Си в два раза больше чем на ASM. Attiny2313

Написал тестовую программу на Ассемблере и Си для Attiny2313.

Программа элементарна, при нажатии на кнопку загорается светодиод, при отпускании гасится.

Вот код на ассемблере:

;##########################################
;## Нажатие на кнопку включает светодиод ##
;##########################################

.include "/usr/share/avra/includes/tn2313def.inc"    ; Подключаем файл описаний
.list                ; Включаем листинг

.def    temp = R16        ; Определение главного рабочего регистра

    .cseg            ; Выбор сегмента программного кода
    .org    0        ; Установка текущего адреса на 0
        
    ldi    temp,    RAMEND    ; Записываем адрес вершины стека в регистр temp
    out    SPL,    temp    ; Записываем адрес вершины стека из регистра temp в регистр стека

    ldi    temp,    0    ; Записываем 0 в регистр temp
    out    DDRD,    temp    ; Записываем 0 из регистра temp в DDRD (порт PD на ввод - кнопка)
    ldi    temp,    0b11111111; Записываем 11111111 в регистр temp
    out    DDRB,    temp    ; Записываем 11111111 из регистра temp в DDRB (порт PB на вывод - LED)

    out    PORTB,     temp    ; Записываем 11111111 из temp в PORTB (тушим светодиод)
    out    PORTD,    temp    ; Записываем 11111111 из temp в PORTD (включаем внутр. резистры)

;--------------- Основной цикл ---------------------;

main:    in    temp,    PIND    ; Читаем содержимое порта PD
            out    PORTB,     temp    ; Записываем содержимое temp в порт PB
            rjmp    main        ; Переход к началу программы

Затем я дизассемблирил HEX файл, получился точно такой же код:

00000000 <.sec1>:
   0:   0f ed           ldi     r16, 0xDF      ; 223
   2:   0d bf           out     0x3d, r16      ; 61
   4:   00 e0           ldi     r16, 0x00      ; 0
   6:   01 bb           out     0x11, r16      ; 17
   8:   0f ef           ldi     r16, 0xFF      ; 255
   a:   07 bb           out     0x17, r16      ; 23
   c:   08 bb           out     0x18, r16      ; 24
   e:   02 bb           out     0x12, r16      ; 18
  10:   00 b3           in      r16, 0x10      ; 16
  12:   08 bb           out     0x18, r16      ; 24
  14:   fd cf           rjmp    .-6            ;  0x10

 

Вот код на Си:

/****************************************
* Prog1.c
* Нажатие на кнопку включает светодиод
****************************************/

#include <avr/io.h>
#include <avr/iotn2313.h>

void main(void) {
  
  DDRB    = 0b11111111; // Во всех разрядах регистра DDRB единицы --> все разряды PB работают на вывод (LED)
  PORTB = 0b11111111; // Во всех разрядах PB единицы и все разряды регистра DDRB работаю на вывод --> тушим Led
  
  DDRD    = 0b00000000; // Во всех разрядах регистра DDRD нули --> все разряды PD работают на ввод (кнопка)
  PORTD    = 0b11111111; // Во всех разрядах PD единицы и все разряды регистра DDRD работаю на ввод --> подключаем внутренние резистры
  
  // Вечный цикл
  while (1) {
    PORTB = PIND;
  }
}

 

После дизассемблера вид такой:

00000000 <.sec1>:
   0:   12 c0           rjmp    .+36           ;  0x26
   2:   17 c0           rjmp    .+46           ;  0x32
   4:   16 c0           rjmp    .+44           ;  0x32
   6:   15 c0           rjmp    .+42           ;  0x32
   8:   14 c0           rjmp    .+40           ;  0x32
   a:   13 c0           rjmp    .+38           ;  0x32
   c:   12 c0           rjmp    .+36           ;  0x32
   e:   11 c0           rjmp    .+34           ;  0x32
  10:   10 c0           rjmp    .+32           ;  0x32
  12:   0f c0           rjmp    .+30           ;  0x32
  14:   0e c0           rjmp    .+28           ;  0x32
  16:   0d c0           rjmp    .+26           ;  0x32
  18:   0c c0           rjmp    .+24           ;  0x32
  1a:   0b c0           rjmp    .+22           ;  0x32
  1c:   0a c0           rjmp    .+20           ;  0x32
  1e:   09 c0           rjmp    .+18           ;  0x32
  20:   08 c0           rjmp    .+16           ;  0x32
  22:   07 c0           rjmp    .+14           ;  0x32
  24:   06 c0           rjmp    .+12           ;  0x32
  26:   11 24           eor     r1, r1
  28:   1f be           out     0x3f, r1       ; 63
  2a:   cf ed           ldi     r28, 0xDF      ; 223
  2c:   cd bf           out     0x3d, r28      ; 61
  2e:   02 d0           rcall   .+4            ;  0x34
  30:   09 c0           rjmp    .+18           ;  0x44
  32:   e6 cf           rjmp    .-52           ;  0x0
  34:   8f ef           ldi     r24, 0xFF      ; 255
  36:   87 bb           out     0x17, r24      ; 23
  38:   88 bb           out     0x18, r24      ; 24
  3a:   11 ba           out     0x11, r1       ; 17
  3c:   82 bb           out     0x12, r24      ; 18
  3e:   80 b3           in      r24, 0x10      ; 16
  40:   88 bb           out     0x18, r24      ; 24
  42:   fd cf           rjmp    .-6            ;  0x3e
  44:   f8 94           cli
  46:   ff cf           rjmp    .-2            ;  0x46

 

Меня интересует, что это за множество переходов в начале, для чего их делает компилятор?

Компилирую так:

avr-gcc -O2 -Os -mmcu=attiny2313 -o Prog1.elf Prog1..c

avr-objcopy -R .eeprom -O ihex Prog1.elf Prog1.hex

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Меня интересует, что это за множество переходов в начале, для чего их делает компилятор?

Похоже на таблицу векторов прерываний.

З.Ы. Компилировать лучше с использованием специального скрипта - Makefile. Редко компилятору нужно задавать менее двух - трех ключей. Следовательно их много, и проще воспользоваться предназначенным для этого файлом, где все это удобно и четко прописано. Оптимизации в подавляющем большинстве достаточно -Os. Возможно она удалит неиспользуемую таблицу векторов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже на таблицу векторов прерываний. ... Возможно она удалит неиспользуемую таблицу векторов.

Это таблица векторов прерываний и есть. Оптимизация не удалит строки в неиспользуемой части таблицы, поскольку это - своеобразная защита "от дурака" на случай если программист случайно разрешит какое-либо прерывание, а соответствующий обработчик написать забудет.

Конечно, при столь маленькой программе "лишние" несколько десятков байт в программе "смотрятся" несколько удивительно, но:

1. При "нормальной" программе эти "лишние" байты - капля в море.

2. Программа на языке высокого уровня при любой оптимизации будет несколько "хуже" программы на ассемблере. Но время на разработку, отладку и сопровождение ПО уменьшается в разы. Отдельные части программы можно написать и на ассемблере (если это необходимо).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

То что код на Си всегда будет больше чем на ассемблере это понятно.

Конкретно эту таблицу векторов прерываний как удалить из этой прошраммы?

Или если дайте почитать про так написать Makefile с нужными опциМи компиляции.

Свои примеры приветствуются!

Изменено пользователем aivs

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Конкретно эту таблицу векторов прерываний как удалить из этой программы?

1)Взять тут файл стартапа.

2)Отредактировать его, выкинув лишнее.

3)Ассемблировать.

4)Слинковать с основным модулем добавив линкеру ключ -nostartfiles.

5)Немного дописать основную программу

6)Убить кучу времени пытаясь понять, почему она перестала работать

7)Понять, что в п.2 удалили лишнее :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

+1

Сейчас как раз идёт активное обсуждение добавления нового ключика к компилятору чтобы он сам использовал свободные вектора под код или данные для своего усмотрения.

Есть даже нечто рабочее в виде патча. Но до коммита в транк ещё видимо очень далеко.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Написал тестовую программу на Ассемблере и Си для Attiny2313.

Программа элементарна, при нажатии на кнопку загорается светодиод, при отпускании гасится.

Вот код на ассемблере:

.....

Затем я дизассемблирил HEX файл, получился точно такой же код:

....

 

Для начала, нужно вернуться к истокам и разобраться, почему "Дизасемблированный HEX файл" из "программы на Ассемблере" дает "точно такой же код".

После этого нужно ответить на вопрос, почему дизассемблированный HEX файл, полученный в результате компиляции из C, содержит другие команды чем исходный Си текст.

И только после этого можно приступать к решению проблемы, которую Вы подняли.

 

Это базовые знания. Без этого понимания сложно что-то делать. Повторять чужое-можно, делать свое хорошего качества и понимать почему результат такой- не получится.

 

Кстати, еще полезно задуматься о том, а зачем Вам эта оптимизация по размеру? как самоцель? Оптимизация должна быть аргументированная и производиться с какой-то целью (например, для достижения необходимой скорости реакции, времени выполнения, размера программы). Просто так оптимизировать чтобы было оптимально- это бесконечный и никому не нужный процесс.

 

2. Программа на языке высокого уровня при любой оптимизации будет несколько "хуже" программы на ассемблере. Но время на разработку, отладку и сопровождение ПО уменьшается в разы. Отдельные части программы можно написать и на ассемблере (если это необходимо).

Например, у компиляторов есть такая интересная оптимизация как "Procedural Abstraction". Так оно иногда такие хитрые финты выкидывает по многократному использованию кода, что в здравом уме на ассме долго думать придется чтобы такой компактности достичь :)

Про "в разы меньше времени на Си чем на ассме"- это Вы не правы. Не в разы, а в тысячи и миллионы раз легче, особенно если речь идет о сопровождении (Само собой, я не говорю о лампочке).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1)Взять тут файл стартапа.

2)Отредактировать его, выкинув лишнее.

3)Ассемблировать.

4)Слинковать с основным модулем добавив линкеру ключ -nostartfiles.

5)Немного дописать основную программу

6)Убить кучу времени пытаясь понять, почему она перестала работать

7)Понять, что в п.2 удалили лишнее :)

:biggrin: полностью поддерживаю, особенно пункт 7 вас должен натокнуть на мысль о том что не стоит оптимизировать что-либо пока вы не достигли размера flash. Вам для чего выйгрыш в нескольких десятках байт?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а в тысячи и миллионы раз легче, особенно если речь идет о сопровождении (Само собой, я не говорю о лампочке).
То есть Вы утверждаете, что потратите час на написание или сопровожддение некого кода на С, а тот же код на асме (применительно к 8 бит Атмелу, а не GUI или СУБД больших машинах) будет отработан за 10е6 часов то есть 114 лет? Что-то неверится. Применительно к "мелким" 8 бит МК может и не нескольких раз не набраться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

То есть Вы утверждаете, что потратите час на написание или сопровожддение некого кода на С, а тот же код на асме (применительно к 8 бит Атмелу, а не GUI или СУБД больших машинах) будет отработан за 10е6 часов то есть 114 лет? Что-то неверится. Применительно к "мелким" 8 бит МК может и не нескольких раз не набраться.

Скорее так: нужно по-быстрому поменять несколько мест в нескольких программах (объемом 10К строк). Может алгоритм поменять, может тип данных, структурку и т.п. На C такие действия тривиальны, на ASM врагу не пожелаешь))

Да, и к Ctrl-C, Ctrl-V вариант C дружественнее...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

пункт 7 вас должен натокнуть на мысль о том что не стоит оптимизировать что-либо пока вы не достигли размера flash.

Не стоит отпимизировать...

Гораздо лучше вести проект с выключенной оптимизацией и когда он достигнет размера flash (килобайт 100-200) вдруг возникнет необходимость ещё в десятке-другом кБ, а его и нет...

И вы окажетесь с проектом на несколько десятков тысяч строк кода, который неизвестно как себя поведёт при включённой оптимизации.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

оптимизация на С, С++ дает хорошую экономию места, но некоторые места (например дрыганье выводами) приходиться "защищать" от оптимизации, иначе компилятор может выкинуть часть кода.

 

с ассемблерном много возни, особенно на переходы с близких на дальние.

были проекты до 8К асм с каруселькой на 7 процессов

 

Итого: если плохо знаешь свой инструментарий, то будет плохо, иначе наоборот

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Например, у компиляторов есть такая интересная оптимизация как "Procedural Abstraction". Так оно иногда такие хитрые финты выкидывает по многократному использованию кода, что в здравом уме на ассме долго думать придется чтобы такой компактности достичь :)

а можно про эту штуку поподробнее ?

есть ли она на avr-gcc и если да, то где она включается ?

Спасибо)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...