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

Программист

Отправить сообщение

Предлагаю завершить дискуссию и подвести итоги. Здесь я высказываю свое мнение и оставляю за Вами право согласиться с ним или остаться при своем мнении.


  1. Начальный вопрос был об оптимизации кода, путем использования регистров r0 и r1 для хранения констант 0 и 1 на постоянной основе. Основание — аналогия с процессором TI. Не согласен. Свои доводы я изложил. Каких-либо доказательств, свидетельствующих о том, что подобная практика позволяет усовершенствовать код не увидел.
  2. Бесполезность MUL, и как следствие, возможность использования регистров r0 и r1 для хранения констант. В процессе дискуссии представленный финальный код содержит MUL. Могу предположить, что доводы о том, что использование всего спектра возможных команд позволяет писать более оптимальный код были услышаны.
  3. Оптимизация циклов за счет выравнивания блоков данных в коде. Здесь я соглашусь с тем, что подобное может быть использовано, но только с определенными оговорками. Во-первых можно вести речь только об оптимизации скорости, но не размера кода. Посчитаем: (31*10)/8196 = 0,037 — коэффициент использования памяти для выровненных блоков данных, размером 10 байт. Плохая реклама с точки зрения оптимизации размера кода. Если рассматривать что-то более приемлемое, например одну таблицу, выровненную по минимальному сегменту (16 байт), то потеря на выравнивание составит всего 6 байт. Экономия по командам для версии "в цикле" — 4 команды. Оптимизация по размеру довольно сомнительна.
    Практика оптимизации, путем выравнивания хорошо применима к сегменту .DSEG, если используется изменение порядка размещения массивов и переменных в памяти для их выравнивания по границам минимального сегмента. В этом случае, потерь как правило, удается избежать.
    Итого: выравнивание по границе блоков данных в .CSEG следует применять только с точки зрения повышения быстродействия, если суммарное увеличение размера кода допустимо.
  4. Замена циклов линейным кодом. Здесь так же вопрос оптимальности. Потери на организацию цикла — 2 команды и 3 тика на каждый цикл, (с учетом инициализации еще 1 команда и 1 тик на весь код). Выигрыш от "разматывания" на один цикл таким образом составит [количество тиков цикла + 3]/[количество тиков цикла]. Увеличение же размера кода при этом получается кратным количеству циклов. В приведенном примере выигрыш по скорости составит ок 17%, а размер кода при этом увеличится примерно в 3,7 раза.
    Я предполагаю, что в результате каждый остался при своем мнении по большинству рассматриваемых вопросов, но в любом случае спасибо за интересную дискуссию.

У Вас в какое место указатель Z показывает перед LPM? Приведите работающий код, который можно запустить и померять размер и производительность.

lpm ZL, Z

Извините, Вы действительно программируете на ассемблере AVR и поняли, что делает подпрограмма? Вы пробовали свой бред запускать?

Так же замечу, что когда я пишу «sts MY_VAR, ONE», или что-то подобное, то я не такты экономлю, а свое время.
Использовать константы в регистрах конечно можно, но только временно и для оптимизации множественных присвоений. Если больше нравится ZERO а не 0 есть директива .EQU ZERO = 0

Попробуйте читать ответ целиком, а не отдельные фразы. Если хотите возложить оптимизацию на компилятор, то Вам к языкам ВУ. В ассемблере такого понятия нет в принципе. А здесь речь идет именно про ассемблер.


типовой понятный или переносимый код

Вы это про что? Про то, что вы собираетесь переносить ассемблерный код под другой тип процессоров? Под TI или ARM или C51? Или даже в пределах AVR c Mega на Tiny. Вы серьезно?
Если нужно разжевать, вот пример подпрограммы для преобразования 4-х байтного BCD числа в 8-и разрядный 7-и сегментный код.


.include "macro.inc"
.DEF    TempL = r16
.DEF    TempH = r17
.DEF    cnt = r18
.DEF    const = r19
.DEF    ZERO = r13
.DEF    PtrL = r14
.DEF    PtrH = r15
...
CnvBCDto7seg:
    clr     ZERO
    ldiw    Z, C7S<<1
    movw    PtrH:PtrL, ZH:ZL    
    ldiw    Y, SRC
    ldiw    X, DST
    ldi     cnt, 4
    ldi     const,16
loop:
    ld      TempL, Y+
    mul     TempL, const; тот самый код разбиения на нибблы
    swap    R0          ; тот самый код разбиения на нибблы
    add     ZL, R1      
    adc     ZH, ZERO
    lpm     TempL, Z
    st      X+,TempL
    movw    ZH:ZL, PtrH:PtrL
    add     ZL, R0
    adc     ZH, ZERO
    lpm     TempL, Z
    st      X+,TempL
    dec     cnt
    brne    loop
    ret

C7S: .DB 0x3F,0x6,0x5B,0x4F,0x66,0x6D,0x7D,0x7,0x7F,0x6F
.DSEG
SRC:    .BYTE 4
DST:    .BYTE 8

Напишите свой вариант и докажите, что Ваш подход лучше.

Я не совсем понимаю темы дискуссии. Вы хотите доказать, что подход к оптимальному программированию на ассемблере не зависит от системы команд процессора и количества и возможностей регистров или все это не имеет отношения к архитектуре процессора?
Что касается Вашего примера. Из 4 команд и 5 тактов по факту нужны 2 команды и 3 такта против 4 команд и 4 тактов. Все остальное можно убрать. В описании задачи нет условия обязательного размещения результата в конкретном регистре (кто мешает производить последующие операции с результатом не таская данные с места на место? ), а константа может быть назначена один раз и использоваться для группы операций.
Что касается использования 0 и 1 в качестве FALSE/TRUE — использовать целый регистр (байт памяти) для хранения битового значения с учетом особенностей реализации условных переходов это как-то не комильфо. Есть более простой и эффективный способ хранения и работы с булевыми переменными.
В целом создается впечатление, что вы изучали подробно TI, а теперь пытаетесь проецировать полученный опыт применительно к ассемблеру AVR.

И ссылку привел на авторитетный источник — документацию по TI MSP430.

Ключевая фраза. Нельзя переносить решения от одного МК на другой. Вы берете рецепт от неймановского PDP11, где нет ни инкрементов ни декрементов и переносите на гарвардовский процессор с абсолютно другой системой команд. В TI константы нужны для операций, которые в AVR без всяких констант итак есть. Если я не прав — приведите часто встречающиеся операции для AVR, где без 0 и 1 не обойтись.
Что касается полезности MUL — подумайте, как можно поделить байт на нибблы в разные регистры без mul. А потом с использованием mul.

Приведите, пожалуйста, какой-нибудь осмысленный код для AVR в пользу своих рассуждений. Тот, где долгосрочное хранение констант 0 и 1 в регистрах уменьшает размер кода или увеличивает скорость работы. Что касается небольших блоков, то я уже писал, что ВРЕМЕННОЕ хранение часто используемой константы для оптимизации не только возможно, но и приветствуется. Только не глобально и в фиксированных регистрах 0 и 1, а в целях оптимизации конкретные значения там, и где это оправданно. Как пример — подпрограмма расчета CRC8. В ней в цикле используется константа 0x31 в регистре tmp1. При этом после выхода из подпрограммы регистр tmp1 используется для других целей.


calc_crc8:
   eor tmp,tmp1 
   ldi crc_tmp,8 
   ldi tmp1,0x31 
lab_crc:
   lsl tmp 
   brcc only_lsl
   eor tmp,tmp1 
only_lsl: 
   dec crc_tmp 
   brne lab_crc
ret_crc:
ret

Упоминание MSP430 в рассуждениях, касающихся ассемблера AVR выглядит несколько странно, с учетом архитектурных различий и, соответственно, набора инструкций. Что касается места хранения констант (r0 и r1), то это вообще не самое удачное место. Почитайте спецификацию команд MUL.

MOV rx,ZERO заменяется на LDI rx,0, если правильно пользоваться регистрами и использовать старшие 16 по назначению. А для хранения всех констант все равно регистров не напастись. Регистров всего 32 а возможных значений 256. Использовать константы в регистрах конечно можно, но только временно и для оптимизации множественных присвоений. Если больше нравится ZERO а не 0 есть директива .EQU ZERO = 0
Нет сомнений, что большинство приведенных макросов так или иначе уже многократно были реализованы. В статье я постарался донести мысль о том, что удобство использования макросов не только в их наличии, но и в интуитивно понятном именовании. LOAD и STORE у меня например никак не ассоциируется с командами, которые они заменяют, в отличии от именования основных инструкций, где есть определенная логика префиксов и суффиксов. Это мое мнение и оно может не совпадать с Вашим.
В отличие от прочих способов использование макросов позволяет видеть и сжатую форму (только макросы) и полный ассемблерный текст. Визуализацией можно управлять при помощи директивы .listmac. Смотрим листинг и имеем полный контроль. Кроме этого я сознательно включил в статью только такие примеры макросов, реализация которых практически однозначна.
Вы правы. Спасибо, что заметили. Исправил.
А в чем смысл? Использовать регистры для хранения констант?
Да, возможно. Сам принцип построения библиотеки это позволяет. К сожалению, для ESP пока недостаточно документации. Из этих соображений, более перспективной выглядит серия процессоров STM
К сожалению, Вы сделали абсолютно неправильный вывод из неверных предпосылок. Библиотека не является компилятором в том представлении, которое Вы в это вкладываете. И она действительно сделана совсем иначе. То, что я представляю, это подключаемая к консольному приложению C# библиотека. И исходная программа для AVR это не текст, который эта библиотека парсит, а программа на C#, со всеми возможностями IDE и языка C#, содержащая за счет использования библиотеки возможность в процессе своего выполнения формировать ассемблерный код. С точки зрения программиста, он пишет на самом обычном C# (ни к языку C, ни даже к C++ этот синтаксис не имеет никакого отношения) консольную программу, результатом работы которой является текст ассемблера. Что касается оптимизации — библиотека как раз и писалась исключительно в целях дать возможность максимальной оптимизации и 100% контроля над кодом. И именно из этих соображений результатом работы является не бинарный код, а аннотированный ассемблер. Более подробную информацию какой код генерит библиотека можно найти в предыдущих частях статьи. В дальнейшем я возможно напишу отдельную статью о принципах, на которых она работает.
Уточните пожалуйста, с какого момента возникли трудности. Если где-то недостаточно объяснений, я посмотрю, как более подробно описать то, что вызывает сложности в восприятии. Библиотека тоже может использовать процедуры, но объем статьи не позволяет затронуть все аспекты сразу. В следующей статье я как раз и планировал описать в том числе использование подпрограмм и процедур
Советую ознакомится с visualstudio.microsoft.com/ru/vs/community/?rr=https%3A%2F%2Fwww.microsoft.com%2Fru-ru%2Fsearch%3Fq%3Dvisual%2Bstudio%2B2013. Заодно еще раз обратите внимание на то, что версия Community абсолютно бесплатна. Все возможности, которые там описаны, справедливы и для этого решения, так как это просто программа на C#. Для того, чтобы пользоваться библиотекой, желательно знать, что такое C# и как на нем программировать. В этом случае все Ваши знания об удобстве и предпочтительности различных IDE для C# будут справедливы и для данного проекта
Давайте рассматривать эту библиотеку как сильно выросшие ассемблерные макросы. С этой точки зрения неважно о какой архитектуре идет речь. Масштабирование, если я правильно понял вопрос, это описание отличающихся объектов для каждой из архитектур и уникальный код ассемблерной реализации. С точки зрения написания универсального кода для всех архитектур этот продукт не очень подходит. В балансе оптимальность/универсальность здесь существенный перекос в сторону оптимальность.
Что касается отладки — библиотека заканчивается текстом ассемблера (не кодом, а именно исходным текстом, без всяких изменений приведенным в примерах в статье). Помощь в отладке заключается в возможности в исходном тексте указывать именованные метки, имена регистров, комментарии для размещения в выходном ассемблере.
Спасибо за оценку. Что касается Linux — то здесь все просто. Библиотека собирается и под Core (спасибо Microsoft за то, что не обходит вниманием и другие ОС). Что касается остального — дождитесь пожалуйста следующей публикации.
1

Информация

В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Зарегистрирован
Активность