- PVSM.RU - https://www.pvsm.ru -
Если у вас есть опыт создания ПО и вы хотите познакомиться с проектированием цифровых логических схем (digital design), то одна из первых вещей, которые вам нужно понять, — это концепция тактов. Она раздражает многих программных инженеров, начинающих HDL [1]-проектирование. Без использования тактов они могут превратить HDL в язык программирования с $display
, if
и циклами for
, как в любом другом языке. Но при этом такты, которые новички игнорируют, — зачастую один из основополагающих элементов при проектировании любых цифровых логических схем.
Ярче всего эта проблема проявляется именно при рассмотрении первых схем, созданных начинающими HDL-разработчиками. Я недавно общался с некоторыми из них. Новички опубликовали свои вопросы на форумах, которые я читаю. Когда я проанализировал то, что они делают, от увиденного волосы встали дыбом.
Например, один из студентов попросил объяснить, почему никого в сети не заинтересовала его HDL-реализация AES [2]. Не стану смущать его, приводить ссылку на проект или имя его создателя. Вместо этого я буду называть его студентом. (Нет, я не профессор [2].) Так вот, этот студент создал Verilog [3]-схему, в которой AES-шифрование выполняется в течение не одного раунда, а каждый раунд, с комбинаторной логикой без тактов. Не помню, какой именно AES он применил, 128, 192 или 256, но AES требует от 10 до 14 раундов. В симуляторе его движок шифрования работал идеально, при этом на шифрование/дешифрование своих данных он использовал только один такт. Студент гордился своей работой, но не мог понять, почему те, кто её смотрел, говорили ему, что он мыслит как программный инженер, а не аппаратный.
Иллюстрация 1. Программное обеспечение последовательно
Теперь у меня есть возможность дать советы программным инженерам вроде того студента. Многие из них обращаются с HDL как ещё с одним языком для написания приложений. Имея опыт программирования, они берут основы из любого софтверного языка программирования — как объявлять переменные, как сделать выражение «если», оператор выбора, как писать циклы и т. д., — а затем пишут код как компьютерную программу, в которой всё выполняется последовательно, при этом полностью игнорируя реалии проектирования цифровых логических схем, где всё происходит параллельно.
Иногда эти программисты находят симулятор вроде Verilator [4], iverilog [5] или EDA playground [6]. Тогда они используют в своей логике кучу команд $display
, обращаясь с ними, как с последовательными printf
, заставляя код работать без применения тактов. Затем их схемы «работают» в симуляторе с использованием одной лишь комбинаторной логики.
И потом эти студенты описывают мне свои схемы и объясняют, что они «без тактов».
Знаете что?
Дело в том, что никакая цифровая логическая схема не может работать «без тактов». Всегда существуют физические процессы, создающие входные данные. Все эти данные должны быть валидны на старте — в момент, формирующий первый «тик» тактового генератора в схеме. Аналогично некоторое время спустя из входных данных нужно получить выходные. Момент, когда все выходные данные валидны для данного набора входных данных, образует следующий «такт» в «бестактовой» схеме. Возможно, первый «тик» — это когда настроен последний переключатель на плате, а последний «тик» — когда глаза считывают результат. Неважно: такт существует.
В результате, если кто-то утверждает, что в его схеме «нет тактов», то это означает, что либо он каким-то неестественным образом использует симулятор, либо у его схемы есть какой-то внешний такт, задающий входные данные и считывающие выходные — и тогда получается, что на самом деле такты есть.
Если вы пытаетесь понять необходимость тактов при работе над цифровой логической схемой либо если вы знаете кого-то, кто ломает голову над этой концепцией, то эта статья для вас.
Давайте пока обсудим такт и важность постройки и проектирования вашей логики вокруг него.
Первая и, вероятно, самая трудная часть изучения аппаратного проектирования заключается в том, чтобы осознать, что вся аппаратная архитектура параллельна. Ничто не выполняется последовательно, как одна инструкция за другой (см. иллюстрацию 1) в компьютере. На самом деле всё происходит за раз, как на иллюстрации 2.
Иллюстрация 2. Аппаратная логика работает параллельно
Это многое меняет.
Иллюстрация 3. Программный цикл
Первое, что должно измениться, — сам разработчик. Научитесь мыслить параллельно [7].
Хороший пример, иллюстрирующий это различие, — аппаратный цикл.
В ПО цикл состоит из серии инструкций, как на иллюстрации 3. Они создают набор начальных условий. Затем в цикле применяется логика. Для определения этой логики используется переменная цикла, которая часто инкрементируется. Пока эта переменная не достигнет состояния прерывания, процессор будет циклически повторять инструкции и логику. Чем больше раз прогоняется цикл, тем дольше выполняется программа.
Аппаратные циклы на базе HDL работают совсем не так. Средство синтеза (synthesis tool) HDL использует описание цикла для создания нескольких копий логики, все они выполняются параллельно. Нет нужды синтезировать логику, используемую для создания цикла, — например индекс, инкрементирование этого индекса, сравнение индекса с финальным состоянием и т. д., — поэтому её обычно убирают. Более того, поскольку средство синтеза создаёт физические соединения и логические блоки, количество прохождений цикла не может изменяться после завершения синтеза.
Получающаяся структура показана на иллюстрации 4. Она очень отличается от структуры программного цикла на иллюстрации 3.
Иллюстрация 4. Цикл, сгенерированный HDL
Из этого есть ряд следствий. Например, итерации циклов необязательно зависят от выходных данных предыдущих итераций, как в ПО. В результате трудно прогонять цикл логики по всем данным в наборе, получая ответ в следующем такте.
Но… теперь мы снова вернулись к концепции цикла.
Цикл — это основа любой FPGA [8]-схемы. Всё вращается вокруг него. Вся разработка вашей логики должна начинаться с такта. Это не второстепенная вещь, такт в первую очередь формирует структуру вашего
Сначала нужно понять, что все операции, которые вы проектируете в цифровой логической схеме, выполняются аппаратно в течение какого-то времени. Причём разные операции длятся по-разному. Переход с одного края микросхемы на другой занимает время.
Эта мысль изображена на графике. Давайте поместим сверху входные данные для нашего алгоритма, в середине — логику, а внизу — выходные данные. Ось времени отложим сверху вниз, от одного такта до другого.
Иллюстрация 5. Выполнение логики занимает время, три операции
На иллюстрации 5 показано несколько операций (сложение, умножение) и несколько раундов применения AES, хотя для нашего примера это могут быть раунды любого другого алгоритма. Вертикальный размер блоков характеризует длительность каждой операции. Кроме того, операции, зависящие от других операций, идут друг за другом. То есть если вы хотите в пределах такта выполнить много раундов применения AES, то имейте в виду, что второй раунд не начнётся до тех пор, пока не завершится первый. Следовательно, внедрение такой логики увеличит длительность между тиками тактов и замедлит общую тактовую частоту.
Посмотрите на розовые блоки.
Они отражают потери активности вашей аппаратной схемы (hardware circuit) — время, которое можно было бы потратить на выполнение каких-то операций. Но поскольку вы решили дождаться завершения такта или ждёте, чтобы сначала обработать входные данные, то вы ничего не можете делать. Например, на этом графике умножение длится не больше одного раунда применения AES, как и сложение. Однако вы не можете ничего сделать с результатами этих двух операций, пока выполняются вычисления AES, потому что для получения их следующих входных данных нужно дождаться следующего такта. То есть розовые блоки — это время простоя электронной схемы. Причём в данном случае оно увеличено из-за того, что раунды применения AES отдаляют следующий такт. Так что такая схема не сможет использовать всех возможностей оборудования.
Если бы нам нужен был лишь конвейер применения AES-алгоритма, чтобы один раунд мог быть вычислен в каждом такте, то схема могла бы работать быстрее, тратя меньше времени на ожидания.
Иллюстрация 6. Разбиение операций для ускорения тактов
После разбиения операции на более мелкие операции, каждая из которых может быть выполнена между тиками тактов, потери активности сильно уменьшаются. Причём вместо шифрования только одного блока данных за раз мы можем превратить алгоритм шифрования в конвейер. Получившаяся логика не будет шифровать одиночный блок быстрее, чем на иллюстрации 5, но если поддерживать наполненность конвейера, то это в 10—14 раз увеличит скорость AES-шифрования.
Это следствие более качественной архитектуры.
Можно ли сделать ещё лучше? Да! Если вы знакомы с AES, то знаете, что каждый раунд состоит из дискретных шагов. Их тоже можно раскидать, ещё больше увеличив скорость такта, пока выполнение логики AES-раунда не станет занимать меньше времени, чем умножение. Это увеличит количество сложений и умножений, которые вы можете выполнить, так что разложение движка шифрования на микроконвейеры позволит пропускать за такт ещё больше данных.
Неплохо.
Также на иллюстрации 6 показана парочка других вещей.
Во-первых, будем считать стрелки задержками при маршрутизации (routing delays). График не масштабный, это лишь иллюстрация для отвлечённой дискуссии. Каждая часть логики должна получать результат предыдущей части логики. Это означает, что даже если какой-то части логики не требуется времени для выполнения — как если бы просто менялся порядок проводов, — то переход логики с одного конца микросхемы к другому всё же займёт время. Следовательно, даже если вы максимально упрощаете свои операции, всё равно будут задержки на перемещение данных.
Во-вторых, вы могли заметить, что ни одна стрелка не начинается с начала такта. И ни одна не доходит до следующего такта. Это сделано для иллюстрирования концепции времени установки и удержания (setup and hold timing). Триггеры [10] — это структуры, которые удерживают и синхронизируют ваши данные в такте. Им нужно время до начала такта, чтобы данные стали постоянны и определены. Хотя многие считают, что такт начинается мгновенно, на самом деле это не так. В разных частях микросхемы он начинается в разное время. И это тоже требует буфера между операциями.
К каким заключениям можно прийти в результате этого урока?
Получается, что при сбалансированной архитектуре в тактах нужно располагать более-менее равное количество логики на протяжении всей схемы.
Теперь вы знаете, что вам необходимо работать с тактами. Как вы измените или построите свою схему в свете этой информации? Правильный ответ: вы ограничите количество логики в тактах. Но насколько ограничить и как это понять?
Один из способов определения оптимального количества логики в такте — задать среднее значение скорости тактов, а затем построить схему с помощью набора инструментов, которые понимают ваше оборудование. Каждый раз, когда схема не будет соответствовать требованиям тайминга, вам придётся возвращаться назад и разбивать компоненты схемы либо замедлять тактовую частоту. Нужно иметь возможность использовать свои инструменты проектирования для поиска наиболее длинного пути.
Сделав это, вы освоите ряд эвристических правил, которые потом будете использовать для вычисления количества логики в тактах применительно к оборудованию, с которым вы работаете.
Например, я хочу построить схему с тактовой частотой 100 МГц с деталями серии Xilinx 7. Эти схемы потом обычно работают на 80 МГц и на Spartan-6 либо на 50 МГц и на iCE40 — хотя это и не строгие сочетания. На одном чипе пойдёт нормально, другой чип окажется избыточно мощным, на третьем появятся проблемы с проверкой синхронизации (timing check).
Вот несколько примерных эвристических правил, относящихся к тактам. Поскольку это эвристика, вряд ли она применима для всех видов схем:
Эти правила — не более чем эвристика, которой я пользуюсь для определения того, сколько логики помещается в такты. Это зависит от оборудования и скорости тактов, так что вам может и не подойти. Рекомендую выработать свои эвристики.
Возможно, лучший совет, что я могу напоследок дать новичкам-разработчикам FPGA, — это изучать HDL, параллельно практикуясь на реальном оборудовании, а не на одних лишь симуляторах. Инструменты, связанные с реальными аппаратными компонентами, позволят вам проверять код и необходимые тайминги. Кроме того, разрабатывать схемы для быстрых тактов — хорошо, но в аппаратном проектировании на этом свет клином не сошёлся.
Помните, аппаратная архитектура по своей природе параллельная. Всё начинается с такта.
Автор: Barrayar
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/kriptografiya/265385
Ссылки в тексте:
[1] HDL: https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F_%D0%B0%D0%BF%D0%BF%D0%B0%D1%80%D0%B0%D1%82%D1%83%D1%80%D1%8B
[2] AES: https://ru.wikipedia.org/wiki/Advanced_Encryption_Standard
[3] Verilog: https://ru.wikipedia.org/wiki/Verilog
[4] Verilator: https://www.veripool.org/wiki/verilator
[5] iverilog: http://iverilog.icarus.com/
[6] EDA playground: https://www.edaplayground.com/
[7] Научитесь мыслить параллельно: http://zipcpu.com/blog/2017/08/21/rules-for-newbies.html
[8] FPGA: https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D0%B0%D1%8F_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B5%D0%BC_%D0%B2%D0%B5%D0%BD%D1%82%D0%B8%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D0%B0
[9] мышления: http://www.braintools.ru
[10] Триггеры: https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B8%D0%B3%D0%B3%D0%B5%D1%80
[11] ZipCPU : https://github.com/ZipCPU/zipcpu
[12] ALU: http://zipcpu.com/zipcpu/2017/08/11/simple-alu.html
[13] памяти: https://github.com/ZipCPU/zipcpu/blob/master/rtl/core/memops.v
[14] деления: https://github.com/ZipCPU/zipcpu/blob/master/rtl/core/div.v
[15] pipelined routine: https://github.com/ZipCPU/openarty/blob/master/rtl/bigsmpy.v
[16] Wishbone Scope: https://github.com/ZipCPU/wbscope
[17] текущая версия: https://github.com/ZipCPU/wbscope/blob/master/rtl/wbscope.v
[18] Источник: https://habrahabr.ru/post/339688/
Нажмите здесь для печати.