[Из песочницы] Расчет временных ограничений для ПЛИС простым языком

Здравствуйте. Эта статья написана для самых-самых новичков в мире ПЛИС. В ней я попытаюсь максимально просто и понятно рассказать что такое временны́е ограничения (timing constraints), накладываемые на проекты под ПЛИС.

Статья создана на основе собственного опыта попыток объяснить тему самому себе, студентам-практикантам и любопытным коллегам так, чтобы не погружаться в заумные академические дебри, а максимально просто, прозрачно, на пальцах. Я учился работать с ПЛИС без учебы и подготовки и знаю по своему опыту как трудно что-то понять не имея теоретического базиса в этой теме и в схемотехнике. Если на данную статью наткнется некий мэтр и воскликнет, что описанное — элементарно, то посмею не согласиться. Для какого-нибудь студента четвертого курса статья будет полезной и поможет разобраться во всех этих слэках, сетапах и холдах.
В статье я буду использовать термины с дублированием их английского варианта в скобках. Это делается потому, что единая терминология не устоялась, а с дублированием проще понять о каком понятии идет речь и при необходимости найти информацию о нем в англоязычных источниках.

Введение


Проведу короткое введение на языке простых понятий.

Для того, чтобы в ПЛИС что-то работало, в нее нужно загрузить (залить, зашить) файл прошивки, с помощью программатора и утилиты прошивания. Файл прошивки является продуктом компиляции САПРом некоторого проекта — папки с файлами, каждый из которых описывает какую-либо сторону проекта. В простых случаях пользователь описывает сам лишь файлы с исходным кодом, файл с распиновкой и файл с временны́ми ограничениями. Из этой триады только файл временны́х ограничений является формально необязательной частью проекта. Собственно, если ваш проект не содержит частот выше 30–50 МГц, то вполне вероятно, что этот файл и не пригодится. Однако, если проект содержит высокие тактовые частоты и не укомплектован файлом временны́х ограничений, то вы не узнаете о том, что ваш проект не будет успевать обрабатывать данные.

Файл временны́х ограничений призван дать компилятору необходимые указания для расчета всех длительностей передач данных в ПЛИС. Пользуясь результатами такого расчета разработчик может видеть в каких частях проекта есть запас по времени, а следовательно и по частоте, а где такого запаса нет.

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

Таким образом, синхронные схемы состоят из межрегистровых передач данных (RTL, register transfer logic, r2r transfer). И ключевой аспект временного анализа состоит в измерении слэка (slack). Это слово буквально переводится как «провисание», «запас по времени», но в русскоязычной среде чаще употребляют кальку с английского — «слэк». В рамках межрегистровой передачи речь идет о слэках предустановки (Setup) и слэках удержания (Hold).

Межрегистровая передача


Межрегистровая передача (рис. 1) рассматривается как система из двух последовательно включенных регистров, которые работают на синхронных в общем случае клоках. В простом случае — на одном клоке. Один регистр является источником (source), а другой является получателем данных (destination). Между ними на пути данных находится некая произвольно определенная пользователем комбинационная логика. Она несинхронная так как не имеет в себе элементов памяти с синхронизирующим сигналом, наподобие регистров. Эта логика — и есть то поведение, те логические операции, которые пользователь описывает своим кодом. Регистры — это те однобитные «переменные», которым пользователь дает имена в коде и оперирует по отдельности, либо объединяя в вектора и массивы.

image
Рис. 1. Схема передачи данных от регистра к регистру

Существует два понятия, связанные с приемом данных регистром-получателем: Setup time и Hold time. Они очерчивают собой диапазон времени, в течение которого сигнал на входе получателя должен быть стабильным и актуальным. Стабильным — по существу означает, что его напряжение должно быть очень близко к одному из двух логических состояний — »0» или »1», а не болтаться между ними с вероятностью перепутывания. Актуальным — означает, что этот бит информации должен по смыслу относиться к этому такту клока, который его захватит, а не запоздавший бит от предыдущего такта.

Setup time — время предустановки, минимальное время, за которое до прихода фронта клока сигнал данных уже должен установиться в стабильное состояние.

Hold time — время удержания, минимальное время, которое после прихода фронта клока сигнал данных должен всё ещё удерживаться в стабильном состоянии.

То есть данные на входе получателя должны быть стабильными и актуальными не только в момент прихода фронта клока, но и на протяжении некоторого защитного интервала времени вокруг него (рис. 2), длительностью не менее (Setup_time + Hold_time).

image
Рис. 2. Смысл Setup Time и Hold time как защитного интервала

Величины Setup time и Hold time жестко определены производителем ПЛИС. Они зависят от технологии производства кристалла и для анализа считаются константами, одинаковыми для каждого регистра в кристалле. В любом случае, эти величины никак не зависят от пользователя, их учет является задачей только для утилиты временного анализа. Нам важно только знать что они существуют и не равны нулю.

Суть временного анализа заключается в том, чтобы для каждой пары регистров в проекте, между которыми есть прямая передача данных на синхронных клоках, рассчитать запасы по времени (слэки), которые есть у данных на то, чтобы быть стабильными в течение защитного интервала. Таких r2r пар в проекте много, тысячи, а то и миллионы, но каждая из них должна быть проанализирована для того, чтобы убедиться в работоспособности проекта.

Слэков, соответственно, тоже два — Setup Slack и Hold Slack (рис. 3).

Setup Slack характеризует собой запас по времени, который имеют данные от момента стабилизации до начала интервала Setup time.

Hold Slack характеризует собой запас по времени, который имеют данные от окончания интервала Hold time до потери данными стабильности.

Слэки должны быть положительными и на всякий случай чем больше — тем лучше. Если слэк отрицательный — то условие стабильности данных на входе не выполняется и данные будут биться.

image
Рис. 3. Положение слэков во времени

Расчет слэков


Теперь перейдем к тому, как эти слэки рассчитываются. Начнем с Setup Slack.
Рассмотрим схему передачи данных на рис. 4.

image
Рис. 4. Схема передачи данных

Здесь мы вводим такие понятия как фронт запуска, фронт захвата, момент прибытия данных, момент ожидания данных и момент прибытия клока.

Фронт запуска (Launch Edge) — это фронт клока, пришедший на вход регистра-источника и запустивший процесс передачи данных.

Фронт захвата (Latch Edge) — это фронт клока, следующий после Launch Edge через один период клока, который приходит на регистр-получатель и заставляет его захватить данные на входе.

Момент прибытия данных (Data Arrival Time) определяется как время фактического прибытия данных на регистр-получатель.

Момент ожидания данных (Data Required Time) определяется как время, за которое данные должны дойти до получателя до наступления времени предустановки на регистре-получателе.

Момент прибытия клока (Clock Arrival Time) определяется как время прохождения фронта захвата от тактового входа всей схемы к тактовому входу получателя.
Под тактовым входом всей системы обычно понимается выход глобального клокового буфера или выход PLL, то есть единая точка, из которой тактовый сигнал расходится до всех регистров своего тактового домена. В самом примитивном случае это ножка ПЛИС, к которой подведен тактовый генератор.

Как соотносится момент прибытия данных с фронтом запуска?

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

Фронт запуска появляется на тактовом входе системы, затем он за некоторое время доходит до входа регистра-источника, затем за некоторое этот регистр срабатывает и отдает на выход новые данные, затем эти данные проходят через цепи комбинационной логики до регистра-получателя. Рассматривается самый медленный вариант прохода данных, поэтому двое слагаемых идут с приставкой «max».

$Data Arrival Time = Launch Edge + \max t_{CLK} + t_{CO} + \max t_D $


В этой формуле слагаемое фронта запуска по сути несет смысл просто некой произвольно взятой точки отсчета, относительно которой развиваются события.

Слагаемое $\max t_{CLK}$ — это максимальное время, за которое фронт запуска дойдет до тактового входа источника. Анализатор как правило не оценивает точно это время, он просто берет диапазон времени от «точно не менее чем» до «точно не более чем» и в данную формулу подставляет верхнюю границу «точно не более чем». Эта величина не зависит от пользователя. Компилятор сам решает где расположить регистр на кристалле и сам учитывает время прохождения клока до него. Сеть соединений, по которым тактовый сигнал расходится к регистрам, спроектирована таким образом, чтобы тактовый сигнал доходил до любого регистра практически за одинаковое время. Поэтому на самом деле разница между $\max t_{CLK}$ и $\min t_{CLK}$ крайне мала, но все же учитывается.

Слагаемое $t_{CO}$ — это время срабатывания регистра (clock-to-output time), которое регистр тратит на то, чтобы увидев фронт на тактовом входе поменять данные на своем выходе. Анализатор считает эту величину равной для всех регистров на кристалле. Эта величина не зависит от пользователя.

Последнее слагаемое $\max t_D$ — это максимальное время прохождения события (данных) через комбинационную логику между регистрами, которая определяется пользователем. Вот эта величина как раз сильно зависит от пользователя. Она выражает степень громоздкости, неаккуратности создания проекта пользователем. Т.е. слишком сложные аппаратные конструкции, требующие слишком много комбинационной логики, дадут и слишком большое время прохождения данных через эту логику.

Момент прибытия клока на получатель рассчитывается проще:

$Clock Arrival Time = Latch Edge + \min t_{CLK}' $


Это момент, в который фронт захвата дойдет до тактового входа регистра-получателя.
Слагаемое $\min t_{CLK}'$ — это минимальное время, за которое фронт захвата дойдет до тактового входа получателя, то есть по аналогии с предыдущей формулой это время «точно не менее чем». Черточка в данном случае означает что речь идет о тактовом входе получателя, а не источника.

Момент ожидания данных определяется как время, за которое данные должны дойти к получателю до наступления времени предустановки на регистре-получателе:

$Data Required Time = Clock Arrival Time – t_{SU} – CSU$


Слагаемое $t_{SU}$ — это уже известное нам Setup time, которое считается одинаковым для каждого регистра на кристалле. Это время не зависит от пользователя.

Слагаемое $CSU$ — это Clock Setup Uncertainty, неопределенность времени предустановки. Как и любая другая неопределенность во временном анализе CSU не является физическим процессом, а является способом отразить в анализе влияние джиттера или просто способом ввести в анализ защитный интервал времени на всякий случай. Простыми словами, это запас времени на учтение сложноописываемых процессов.

Теперь, когда эти термины определены, мы можем определить слэк предустановки как разницу между временем, которое разрешено потратить на путь до получателя, и временем, которое этот путь фактически займет.

$Clock Setup Slack = Data Required Time – Data Arrival Time $


Теперь раскроем эти слагаемые и немного переставим местами:

$Clock Setup Slack = Latch Edge + \min t_{CLK}' – t_{SU} – CSU -$

$– (Launch Edge + \max t_{CLK} + t_{CO} + \max t_D) $

$Clock Setup Slack = Latch Edge-Launch Edge-\max t_D – $

$-CSU+( \min t_{CLK}'-\max t_{CLK}) – t_{SU} – t_{CO}$

$=Period-\max t_D – CSU+ \min t_{CS} – t_{SU} – t_{CO}$


Здесь появились новые слагаемые.

Про период понятно, это период тактовой частоты, т.е. время между Launch Edge и Latch Edge.
Слагаемое $\min t_{CS}$ — это растекание клока (clock skew) — минимальная величина разброса времени прихода одного фронта клока от тактового входа системы до разные синхронные регистры. Минимальное растекание клока определяется как разница между наименьшей задержкой клока к получателю и наибольшей задержкой клока к источнику $\min t_{CS} = \min t_{CLK}' - \max t_{CLK}$. Анализатор не делает разницы в оценке этого времени для разных регистров на кристалле.

Таким образом мы посчитали слэк предустановки. Положительный запас — хорошо, отрицательный — плохо. Слэк буквально переводится как провисание. Значит если слэк есть — значит межрегистровая передача настроена не «внатяг», условная «ниточка» свободно провисает. Слэк отрицательный — значит ниточка передачи была перетянута и порвалась.

На рисунке 5 показано как формулу слэка можно представить графически:

image
Рис. 5. Графическое представление выражения Setup Slack

Здесь показаны соотношения на фоне тактового сигнала, причем это тактовый сигнал на тактовом входе системы, а не на входе какого-либо из регистров.

Теперь похожим образом рассчитаем слэк удержания.

Его тоже можно представить выражением, в котором слагаемые поменялись знаками:

$Clock Hold Slack = Data Arrival Time – Data Required Time$


Вот только эти слагаемые теперь рассматриваются с другой стороны.

$Data Arrival Time = Launch Edge + \min t_{CLK} + t_{CO} + \min t_D $


Теперь здесь рассматривается самый быстрый вариант прохода данных и там, где было «max» стало «min».

Момент прибытия фронта клока также рассматривается в ином ключе, как самый поздний из возможных:

$Clock Arrival Time = Latch Edge + \max t_{CLK}' $


Важно отметить, что в случае рассмотрения Hold Slack фронты Launch Edge и Latch Edge — это один и тот же фронт, а не два разных фронта, разделенных периодом клока. Регистру-получателю в данной ситуации нужно успеть удержать данные на входе в течение времени удержания от прихода фронта клока. Но данные меняет на его входе этот же фронт, пришедший где-то в другом месте на регистр-источник. Поэтому в анализе слэка удержания разница $Latch Edge - Launch Edge$ равна нулю, а не периоду.

Требуемое время в данном случае определяется как время, за которое данные должны не меняться на входе данных получателя, чтобы не зацепить время удержания:

$Data Required Time = Clock Arrival Time + t_H + CHU$


Слагаемое $t_H$ — это уже известное нам Hold time, время удержания. Оно считается одинаковым для каждого регистра на кристалле и не зависит от пользователя.
Слагаемое $CHU$ — это Clock Hold Uncertainty, неопределенность времени удержания. Оно несет в общем тот же смысл, что и CSU, да и как правило берётся равным ему.

Если, как и в случае со слэком предустановки, раскрыть слагаемые и поменять местами, то выражение слэка удержания можно преобразовать в следующий вид:

$Clock Hold Slack = \min t_D-\max t_{CS} + t_{CO} -t_H - CHU$

$\max t_{CS} = \max t_{CLK}'-\min t_{CLK}$


Ура, мы узнали как рассчитываются слэки. Как использовать эти знания?
Давайте посмотрим на выражения слэков еще раз:

$Clock Setup Slack=Period-\max t_D – CSU+ \min t_{CS} – t_{SU} – t_{CO}$

$Clock Hold Slack = \min t_D -\max t_{CS} + t_{CO} -t_H - CHU$


Если какие-то слэки проекта стали отрицательными, то поменять их мы можем поменяв их слагаемые.

Мы видим слагаемые, которые не зависят от пользователя, а зависят только от технологии кристалла. Это $t_{SU}, t_H, t_{CS}, t_{CO}$.
Мы видим слагаемые CSU и CHU, которые анализатор как правило берет равными параметру CU — Clock Uncertainty, нестабильность тактовой частоты. Этот параметр вообще говоря невелик, десятки пикосекунд. Он указывается пользователем в файле ограничений. А пользователь его в свою очередь берет из спецификации на тактовый генератор. Считается что клоковый буфер или внутренняя PLL ПЛИС, которые принимают внешний клок от генератора и преобразуют во внутренний клок на тактовый вход системы, сохраняют величину CU той же, что получена от генератора. Если CU не указать, то анализатор выставит ей некоторое значение по умолчанию, например Quartus ставит 20 пс. В общем случае это слагаемое говорит нам о том, что лучше использовать для тактирования высокостабильные генераторы с величиной нестабильности порядка 20–60 пс.

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

И, наконец, слагаемое $t_D$ характеризует по сути эффективность написанного кода. Отсюда следует и основной способ решения проблем со слэками — переписать как следует. Большое время $t_D$ появляется у слишком сложных аппаратных конструкции, требующих слишком много комбинационной логики. Если такие сложные конструкции появились у вас в проекте, то классический способ решения проблемы — разбить одну сложную r2r передачу на несколько простых, вставив еще 1–2 регистра в последовательность операций. При этом вырастет задержка в тактах на выполнение операции, но зато увеличится быстродействие операции. Например, сложение за один такт нескольких векторов — это не очень хорошая идея. Складывать несколько векторов лучше по очереди, с промежуточными суммами. Некоторые сложные конструкции бывает невозможно разбить на конвейер из нескольких простых — тогда такую логику нужно переписывать как-нибудь принципиально иначе.

Дополнение


Выше был представлен способ расчета слэков, характерный для человеческого представления о происходящих процессах. Тут «фронт идет…», «данные идут…». Если интересно, то в качестве дополнения расскажу как представляет себе данные расчеты анализатор временны́х ограничений.

Анализатор группирует слагаемые иначе, исходя из своих машинных резонов.
Он оперирует понятиями Clock Setup Relationship (SR) и 
Clock Hold Relationship (HR) — которые можно перевести как соотношение времени между инициирующим фронтами для предустановки и удержания соответственно.

$SR = Setup Latch Edge - Setup Launch Edge-CSU$

$HR = Hold Latch Edge - Hold Launch Edge-CHU$


На рисунке 6 можно увидеть о каких фронтах идет речь:

image
Рис. 6. Фронты, используемые в расчетах слэков.

Можно сразу преобразовать полученные выражения в более понятный вид:

$SR = Period-CSU$

$HR = CHU$


Наибольшее межрегистровое время (Largest r2r Required) это максимальное время, имеющееся для того, чтобы данные дошли к получателю до начала интервала предустановки:

$Largest\ r2r\ Required = SR + \min t_{CS} – t_{CO} – t_{SU}$


Самая длинная межрегистровая задержка (longest r2r Delay) это время, необходимое для передачи данных из исходного регистра в регистр назначения по самому длинному пути:

$Longest\ r2r\ Delay = \max t_D$


Теперь мы можем определить слэк предустановки как разницу между временем, доступным для достижения регистра назначения, и фактическим временем, чтобы добраться туда:

$ClockSetupSlack = Largest\ r2r\ Required –Longest\ r2r\ Delay$


Раскрытие слагаемых этой формулы даст нам уже знакомое представление слэка предустановки:

$Clock Setup Slack=Period-\max t_D – CSU+ \min t_{CS} – t_{SU} – t_{CO}$


Теперь про слэк удержания. Наименьшее межрегистровое требование (smallest r2r Requirement) это время, необходимое для удержания данных на входе регистра назначения:

$Smallest\ r2r\ Required = HR + \max t_{CS} – \min t_{CO} + t_H$


Кратчайшая межрегистровая задержка:

$Shortest\ r2r\ Delay = t_D$


Теперь определяем слэк предустановки как разницу между быстрейшим временем ухода данных со входа получателя и временем, которое требуется их там удерживать:

$ClockHoldSlack = Shortest\ r2r\ Delay – Smallest\ r2r\ Required$


При раскрытии слагаемых выражение также принимает уже знакомый вид:

$Clock Hold Slack = \min t_D -\max t_{CS} + t_{CO} -t_H - CHU$


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

© Habrahabr.ru