Выделение байтов из слова. функции/директивы компилятора/препроцессора

“Напрямую пишущий” ничего не гарантирует. Напрямую тоже можно всякой чуши написать.
Особенно когда этот человек не знает, нужен слвиг влево или нет …

Вообще, по моим наблюдениям. больше всего ратуют за ассемблер те, кто просто не знает СИ

Да не в I2C дело. Приведенную функцию для инициализации дисплея вполне можно написать и на С. На быстродействии это не скажется.
Но ведь у меня там будут и другие функции, и некоторые такие, где максимум можно выжать именно на ассемблере.
Да и для меня ассемблер просто намного проще и визуально понятнее чем С.

Проблема не в том нужен сдвиг или нет. Проблема - нужен ли сдвиг в GNU.
Я подозреваю что он там не нужен потому что там изначально значение уже сдвинуто.

Вполне возможно.

Это утверждение неочевидно и нуждается в доказательстве.
Обычно для коротких фрагментов результат получается один в один. А в случае длинных компилятор, как правило, выигрывает, т.к. может следить за несколькими десятками переменных, а человек - нет.

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

А про тот случай, когда у Вас есть код для AVR, а Вам надо использовать его для STM32, я даже не говорю.

1 лайк

Как правило, и Ассемблера - тоже.

Вот прямо на уровне диагноза: если человек утверждает, что некоторый алгоритм можно записать только на Ассемблере, но нельзя на ЯВУ, это практически на 100% означает, что он не знает ни Ассемблера, ни ЯВУ.

1 лайк

Покажите как вы это видите. LTO может вам сильно навалить …

Ну например когда-то решил поиграться с адресной лентой. Почитал как она работает и написал так:
(в каждом адресном светодиоде 4 светодиода: красный, зеленый, синий и белый. Информация для зажигания одного светодиода передается 32 импульсами)

.ino

extern "C" {
  void start();
  void SetOneLed(byte Red, byte Green, byte Blue, byte white);

.S

#define __SFR_OFFSET 0x00

#include "avr/io.h"

.global start
.global SetOneLed

start:      sbi   DDRB, 5
            cbi   PORTB, 5
            ret

SetOneLed:  cli
            push r26
            ldi r26, 32  ;Передавать будем 32 бита из r22, r24, r20, r18
; Тело цикла должно содержать 20 тактов 6+8+6 (установка бита, задержка 6, условное изменение бита, задержка 8, сброс бита, задержка 6)
cont1:      nop
            nop
            sbi PORTB, 5
            ; прокручиваем все 4 байта, получаем текущий бит в флаге С
            lsl r18    
            rol r20
            rol r24
            rol r22
            brcs send1
            cbi PORTB, 5
send1:      adc r18, r24  ; восстанавливаем утерянный бит из флага С (чтобы к концу работы регистры r22,r24,r20,r18 приняли прежнее значение)
            sub r18, r24  ; надо оно или нет - хз, но тут программе все равно делать нечего, так что это замена nop'ов
            nop
            nop
            nop
            nop
            nop
            cbi PORTB, 5
            dec r26
            brne cont1
            pop r26
            sei
            ret

Где-то читал что первые параметры передаются через регистры от R24 до R8, если параметров сильно много, то остальные через стек.

только один ЛЕД зажигаете?

  1. Я такого не утверждал.
    Приведенный в начале пример - это не из-за того что я решил абсолютно все написать на ассемблере. Просто начала переносить с авр студио и наткнулся на проблему. И решил разобраться с ней возможно на неудачном примере.
    Разумеется, что со временем я бы переписал на СИ часть функций, а часть оставил бы на ассемблере.

Кстати, с помощью objdump посмотрел что там получилось. Оказалось действительно в моем случае при работе с AVRASM сдвиг нужен, а при работе с GNU нет.

А зачем больше?
Функция написанная на ассемблере зажигает, только один.

А вообще я зажигал 300 светодиодов (ленту длиной 5м), только это уже писал на СИ используя вышеупомянутую функцию.

логично…
Хотя почему-то все писатели обычно пишут на асме и выборку данных из внешнего массива.
Хотя как у вас - и правда проще.
Скорость там особо некритична, тайминги с запасом

Это, если ничего другого делать не надо.

Ну да. нужные тайминги при передаче 4 байт одному светодиоду выдержаны благодаря ассемблеру. Так хоть четко знаешь сколько тактов выполняется каждая команда и никаких неожиданностей не будет. А следующий светодиод можно зажечь хоть сразу, хоть спустя некоторое время от зажигания предыдущего. Главное не превысить некоторое критическое время, после которого все начинается сначала.

Делаем массив длиной равной кол-ву светодиодов, шириной 1-4 байта, в зависимости от необходимого кол-ва цветов, в цикле выводим его на ленту и готовим следующий кадр. обычно даже делай вставлять после этого приходилось.
Я делал матрицу из 300 светодиодов 30x10, рисовал там елочку на фоне падающего снега, бегущую надпись, типа “С Новым Годом!!!”, некоторые другие эффекты. На прочее фантазии не хватило. Но быстродействия хватало с запасом. даже задержки дополнительные ставил, чтобы FPS не был слишком высоким, и лента гарантированно успевала сбрасываться. Вернее задержки delay были тем кодом, которые потребляли большую часть процессорного времени.

Можно конечно и без массива. Но так навряд ли получится реализовать несколько объектов движущихся на фоне друг друга, причем в разные стороны

Собственно это хоть и не ответ на первоначальный вопрос, но разобраться с проблемой мне помог именно он.

Три строки в platform.txt и листинг будет создаваться на автомате:

compiler.objdump.cmd=avr-objdump
compiler.objdump.flags=--disassemble --source --line-numbers --demangle --section=.text
recipe.hooks.objcopy.postobjcopy.1.pattern.windows=cmd /C echo. && "{compiler.path}{compiler.objdump.cmd}" {compiler.objdump.flags} "{build.path}/{build.project_name}.elf" > "{build.path}/{build.project_name}_{build.mcu}_{build.f_cpu}.lst"

Если вместо третьей строки вставить:

recipe.hooks.objcopy.postobjcopy.1.pattern.windows=cmd /C echo. && "{compiler.path}{compiler.objdump.cmd}" {compiler.objdump.flags} "{build.path}/{build.project_name}.elf" > "{build.source.path}/{build.project_name}_{build.mcu}_{build.f_cpu}.lst"

То файл с листингом будет лежать там же где лежит скетч.

5 лайков

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

Спасибо!

@glukmaker, не моё, конечно, дело, но Вы бы не злоупотребляли со сдвигами и вообще, с адресной арифметикой. В том же GNU Asm если структуры, они позволяют записать что Вам нужно (примерно, как в С), а об адресах полей ассемблер позаботится.

1 лайк

Компилятор не сможет. Он хуже программиста. Гораздо.

Отлично. А нет ли возможности чтобы предотвратить дизассемблирование тех участков, где находятся данные, а не код?