Excel как транслятор в ассемблер AVR
Предпосылки
Ряд статей (https://habr.com/ru/post/345320/, habr.com/ru/post/80893, habr.com/ru/post/246975) навел на мысли о том, что Excel можно использовать как транслятор в ассемблерный код AVR.
Сопоставим Excel с основными фичами «обычного» редактора кода. Список самых популярных фич следующий:
Выглядит приемлемо. Кое-что достается «даром», кое-что надо доработать.
Но главное отличие табличного процессора от текстового — пользователь может размещать блок информации в произвольном месте пространства, а не только друг под другом. Эту особенность мы используем, чтобы превратить плоский код в почти полноценную блок-схему.
Первоначальные соглашения
Общий подход и терминологию примем отсюда: habr.com/ru/post/345320
Весь алгоритм разделим на ветки. Ветка играет роль самостоятельного программного блока.
У каждой ветки есть имя, которое является точкой входа в нее. Оно должно быть уникальным и осмысленным. Все имена веток размещаются в верхней строке, которую так и назовем — «строка имен».
Ветка заканчивается одним или несколькими переходами к другим веткам. Переходы от одной ветки к другой размещаются в самой нижней строке. Назовем ее «строка переходов».
Также принимаем правило, что изнутри одной ветки нельзя переходить внутрь другой.
Для ветвлений и циклов внутри ветки также применяются метки. То есть меток в программе очень много. Каждый раз придумывать новое уникальное имя — это рутина. Здесь на помощь приходит базовая функциональность Excel. Каждая ячейка уже имеет уникальное имя, состоящее из имени столбца и номера строки.
На VBA создадим функцию label с аргументом типа Range. Метка в ассемблере AVR должна иметь на конце двоеточие. Т.е. наша функция labelполучает на вход ссылку на ячейку, в которой размещается сама и вычисляет ее адрес в формате A1. Затем добавляет к ней текст »_M:». Фрагмент »_M» не случаен, мы будем использовать это дальше — в форматировании ячеек.
Визуализация переходов
В настоящих визуальных средах переходы обозначаются стрелками. Это удобно и наглядно.
В табличном процессоре вместо стрелочек можно подкрашивать ячейки, образующие путь к метке от команды перехода. В примерах так и сделано.
Если получается уместить весь код ветки на один экран, то можно не отрисовывать маршруты. Все команды перехода и метки будут перед глазами.
Для блок-схем существуют стандарты на обозначения отдельных элементов. Например, прямоугольник — это вычисление; ромб — условие и т.д. При работе с табличным процессором нам доступны управление цветом, начертанием и границами.
В Excel есть удобная функция условного форматирования. Использовать ее можно по-разному, но мы введем всего три простых правила:
- Непустая ячейка в строке имен и в строке переходов красится в желтый цвет;
- Непустая ячейка в теле ветки красится в оранжевый;
- Ячейки с «локальными» метками и командами перехода красятся в синий. Это непустая ячейка, которая содержит символы »_М», о которых упоминалось выше.
На гифке ниже представлено, как работа с метками и переходами выглядит после всех настроек.
Порядок формирования конечного листинга
Сборщик листинга обходит итоговую программу сверху вниз и справа налево. По одной ячейке за раз.
Алгоритм сборки пропускает пустые ячейки и ячейки, которые содержат символ »;», т.е. комментарии.
Отладка алгоритма и окончательная сборка проекта происходит в студии. Обратная связь кода в студии с ячейками Excel отсутствует. Поэтому для ловли ошибок в итоговый листинг напротив каждой команды указываем ссылку на ячейку. По этой ссылке мы находим проблемную команду на схеме в Excel.
Базовое алгоритмическое решение — это ветвление вида:
If <условие> then
<действие>
Else
<действие>
End if
Для него в ассемблере AVR есть команды условного перехода (breq, brne, sbic и прочие). Эти команды указывают программе, куда перейти при выполнении условия.
Теперь представим, как должна выглядеть программа такого ветвления с учетом озвученных выше принципов:
У команды brne и ее аналогов есть ограничение. Дальность перехода составляет 64 слова в каждую сторону. Поэтому длинный макрос, вставленный в ответвление «Нет» может вызвать out of range.
Для обхода этого ограничения обработку «Нет» производить в отдельной ветке, которая будет правее метки перехода от brne. Либо использовать подпрограмму, в которой вызывается макрос.
Select Case
Если выбирать приходится из большого количества вариантов, в ЯВУ используется Select Case:
Select Case <переменная>
Case <условие1>
Case <условие2>
Case <условие3>
Case else
End select
На ассемблере под AVR доступны индексные переходы. Покажем вариант реализации.
Здесь видно, что нарушен запрет прыжка из тела ветки к другой ветке. Это сделано преднамеренно, иначе программа займет слишком много места по горизонтали.
По этой же причине вектор прерываний следует выполнить в один столбик.
Цикл с постусловием
Цикл, когда необходимо минимум одно повторение, в нотации ЯВУ выглядит следующим образом:
Do
<действие>
Loop while <условие>
Пример, как это выглядит в Excel и итоговый код в студии:
Цикл с предусловием
Пример на ЯВУ:
Do while <условие>
<Действие>
Loop
Пример, как это выглядит в Excel и итоговый код в студии:
Цикл со вложенным циклом
Обработка массивов или работа с числами предполагает использование вложенных циклов. Общий вид на ЯВУ:
Do
Do
<действие>
Loop while <условие 2-го уровня>
<действие>
Loop while <условие 1-го уровня>
Реализовать вложенный цикл можно двумя путями: либо внутри одной ветки, либо с помощью нескольких веток. Покажем оба варианта.
Цикл с выходом по условию
Есть ситуации, когда из цикла необходимо выйти до его окончания. Например, логический ноль на 0-вой ножке порта D может говорить о какой-то неисправности. Программа должна покинуть основной цикл и запустить тревогу.
В ЯВУ используется команда break, а общий алгоритм имеет следующий вид:
Do
<действие>
If <условие прерывания> then break
Loop while <условие>
Снова покажем, как будет выглядеть алгоритм без веток и с ветками.
Вызов подпрограмм
Подпрограммы вызываются командами call, icall, rcall. Тут есть важная особенность. Подпрограмму необходимо вызывать строго из тела ветки. Если же вызов разместить в строке переходов, возврат из подпрограммы почти гарантированно произойдет в неверное место.
Обязательные требования к подпрограмме:
- сама подпрограмма обязательно начинается с имени-метки;
- последняя команда подпрограммы обязательно должна быть ret и размещаться в строке переходов.
Внутренняя структура подпрограммы может быть произвольной — применяем все те же автоматические метки label для реализации логики.
Пример с бегущим огоньком
Приведем код тестовой программы с бегущим огоньком. Пример включает циклы, ветвления и вызов подпрограммы.
Конечный результат выглядит так:
Листинг всей программы в Excel со скрипом уместился на один экран:
Итоги
Что не понравилось
- Изложенный метод вряд ли подойдет для работы над большим проектом с участием целой команды. Контроль версий, диффы и т.д. все равно придется решать на стороне.
- В режиме отладки очень неудобно без двух мониторов. Сама отладка ведется в студии, а блок-схема в Excel. Это разные окна, требуются переключения.
- Программа быстро пухнет в горизонтальном направлении. При этом в Excel прокрутка в сторону грубая и неудобная.
- Болезнь блок-схема как таковых — много пустого места. Для комфортной работы на одном экране разрешением 1280×1024 должно быть около 5 столбиков и 45 строк с информативными ячейками. Не более 20% от этого количества будет заполнено самими командами (это 45 команд). Остальное пространство — жертва визуальному представлению и комментариям. Примерно столько же команд помещается в окно студии на один экран.
Что понравилось
- Проектирование алгоритма «сверху вниз» складывается очень естественно. Объявляем только имена и переходы.
- Код в Excel можно открыть в несколько окон. В Atmel Studio доступно только разделение экрана по горизонтали.
- Сокращение рутинных действий при работе с именованными сущностями.
- Контроль меток не требует внимания. Переместили или переименовали метку — все переходы автоматически получат изменения. Удаление метки приведет к ошибке, которую легко найти визуально.
- Excel как транслятор очень просто расширять новыми функциями. Что-то доступно через формулы, что-то — через макросы VBA.
Точки роста
- Оптимизация работы с метками и переходами. Если в итоговом листинге команда «Переход на метку» расположена прямо над самой меткой, команду с переходом можно убрать. Освободим 4–5 тактов. Если конструкция вида «Переход на метку А — Метка А — Переход на метку Б — Метка Б» не содержит внутри никаких команд, то «Переход на метку Б» убираем, а «Переход на метку А» меняем на «Переход на метку Б». Также сэкономим 4–5 тактов.
- Дополнительные проверки на ошибки. Макросом легко организовать проверку, нет ли «висящих» блоков, которые не кончаются переходами. Также макросом можем найти и удалить неиспользованные метки, которые при отладке отвлекают внимание.
- Можно ввести собственные правила раскрашивания ячеек.
- Если бы табличный процессор был встроен в студию как редактор кода, то производить отладку сразу на такой блок-схеме было бы очень удобно.