Предлагаю несколько примеров, которые иначе, как этюды на ассемблере, не назовешь. Задачи простые, однако, я старался сделать их решения красивыми. Красивым я называю такой код, который либо реализует оригинальный алгоритм, либо имеет наименьший размер, либо обладает наибольшим быстродействием, либо обладает еще какими-то неординарными параметрами. Этюды имеют и вполне реальную ценность, т.к. посвящены довольно часто встречающимся в практике ситуациям.
ЭТЮД. 1. Произведение вспомогательного характера - рисунок, картина или скульптура - и обычно небольшого размера, выполненное с натуры. 2. Инструментальная пьеса виртуозного характера, предназначенная для концертного исполнения. 3. Небольшое литературное произведение или научное исследование, посвященное какому-л. частному вопросу. 4. Упражнение, служащее для развития и совершенствования техники какого-л. искусства: актерского, шахматного, музыкального и т.п. (обычно импровизационного характера).
Толково-словообразовательный словарь русского языка.
В предложенных этюдах подразумеваются, что имеется следующий код-преамбула:
Ассемблер микроконтроллеров реализует целочисленную арифметику, однако часто требуется увеличить или уменьшить в дробное число раз. Очень многие сразу бросаются писать программы на Си с использованием float-переменных, однако для некоторых частных случаев существуют довольно элегантные решения и на ассемблере. Умножение на 1.25, если вдуматься, это всего-навсего сложение числа с собственной четвертью. И этот алгоритм для байтовых чисел без знака реализуется так:
Ассемблер микроконтроллеров AVR не содержит команды, осуществляющей циклический сдвиг байта вправо и влево, а необходимость в этом возникает довольно часто. Вот как это можно реализовать:
;Циклический сдвиг влево VH (вариант 1) PUSH VH LSL VH POP VH ROL VH
;Циклический сдвиг влево VH (вариант 2) CLR V LSL VH ADC VH, V
Как видите, сдвиг влево можно осуществить двумя способами: без использования дополнительного регистра или с использованием. Первый вариант более медленный и более объемный, зато второму требуется свободный регистр. Попробуйте самостоятельно решить задачу для сдвига вправо, добившись более быстрого кода, по образцу сдвига влево.
Циклические сдвиги бывает необходимо выполнять и над двухбайтными числами, и вот варианты реализации таких сдвигов:
;Циклический сдвиг влево (VH:VL) - вариант 1 PUSH VH LSL VH POP VH ROL VL ROL VH
;Циклический сдвиг влево (VH:VL) - вариант 2 CLR V LSL VL ROL VH ADC VL, V
И снова сдвиг влево реализован разными способами, а для сдвига вправо, надеюсь, вам будет интересно поломать голову и самим.
3. Обращение порядка битов.
Иногда требуется получить «зеркальное» отражение битов в байте, т.е. когда нулевой бит обменивается местами с 7-ым, 1-й с 6-ым и т.д. Условно это можно обозначить так, заменив значения битов буквами: ABCDEFGH --> HGFEDCBA. Даже любители Си знают, что красиво решить эту задачу не так-то просто. И, не смотря на то, что при грамотной записи на языке Си многие компиляторы генерируют весьма компактный код, ассемблер все-же позволяет добиться еще лучших результатов. Решению этой задачи посвящалось много тем на различных форумах, однако я решил эту задачу самостоятельно, причем двумя способами, с которыми предлагаю познакомиться и вам.
;Перестановка порядка битов [ABCDEFGH]-->[ HGFEDCBA] в Temp ; максимум скорости - 14 тактов, 14 команд SWAP Temp MOV Temp1, Temp ROR Temp ROL Temp1 ROR Temp ROL Temp1 ROR Temp ROL Temp1 ROR Temp ROL Temp1 ROR Temp ANDI Temp, 0xF0 ANDI Temp1, 0x0F OR Temp, Temp1
;Перестановка порядка битов [ABCDEFGH]-->[ HGFEDCBA] в Temp ; минимум кода - 11 команд, 26 тактов .DEF Temp2 = <Регистр R16...R31> SWAP Temp MOV Temp1, Temp LDI Temp2, 4 m1: ROR Temp ROL Temp1 DEC Temp2 BRNE m1 ROR Temp ANDI Temp, 0xF0 ANDI Temp1, 0x0F OR Temp, Temp1
Недавно я обнаружил, что найден еще один способ - пока что самый быстродействующий: всего 13 тактов! Но найти его предлагаю вам самостоятельно.