Comments 43
Хм… а почему Вы не стали использовать код грея для передачи указателей фифо через домен? Я думал это стандартное, проверенное временем решение, которое используют все.
Код Грея может спасти только при очень близких частотах. А вот при переходе от 250 МГц к 100 МГц он уже не поможет.
Поясните кейс с 250 / 100 МГц
Счётчик на 250 МГц успеет насчитать несколько значений за один такт 100 МГц. И я не понимаю как здесь может помочь год Грея.
Это не важно сколько он насчитает.
В любой момент времени вы всегда будите видеть либо текущее значение, либо прошлое. Только если у вас шина со значением настолько расползается по времени, что по одним битам успеют придти два значения пока по другим ползет одно. Но это нереальный случай.
А имея в любой момент времени либо старое либо новое значение, при это за счет счетчика грея отличающиеся только на 1 бит, вы не можете неправильно обработать заполнение фифо.
В любой момент времени вы всегда будите видеть либо текущее значение, либо прошлое. Только если у вас шина со значением настолько расползается по времени, что по одним битам успеют придти два значения пока по другим ползет одно. Но это нереальный случай.
А имея в любой момент времени либо старое либо новое значение, при это за счет счетчика грея отличающиеся только на 1 бит, вы не можете неправильно обработать заполнение фифо.
| Только если у вас шина со значением настолько расползается по времени
При асинхронных сигналах тактовой частоты всегда будут ситуации когда разные разряды шины будут защёлкнуты в разное время. Т.е. в другом домене будет часть нового значения а часть старого. А часть вообще будет в метастабильном состоянии. И в этом случае год Грея не поможет.
При асинхронных сигналах тактовой частоты всегда будут ситуации когда разные разряды шины будут защёлкнуты в разное время. Т.е. в другом домене будет часть нового значения а часть старого. А часть вообще будет в метастабильном состоянии. И в этом случае год Грея не поможет.
Ваша реализация точно так же не дает никаких гарантий. В теории сдвиг фазы может превышать может превышать любое число тактовых периодов, если вы не написали constraint синтезатору. В общем реализация с Греем лучше т.к. требует меньше тактов на пересинхронизацию.
Это не так. У меня есть компонент ctrl_retack_counter_m12 Он корректно переводит шину data_in на data_out за несколько тактов. В нём сначала фиксируется значение на data_in, взводится флаг и фиксируется значение на data_out. Далее всё повторяется.
ну смотрите, у вас есть вектор сигналов data который пишется на одном клоке, а читается на другом. Если вы не напишете constraint на этот сигнал, то разные сигналы в этом векторе могут прийти с разной задержкой. На низкой частоте в маленьком дизайне скорей всего все будет правильно работать. Но на высоких частотах задержка может превышать несколько тактов и вы рискуете получить неправильное значение. Я в другом комменте скинул ссылку на статью про этот кейс. Т.е. constraint нужно писать всегда. А раз пишем constraint, то проще делать на грее, т.к. его можно пересинхронизировать обычным двойным флопом
Теперь я понял что вы опасаетесь. Но смотрите что происходит.
Автомат pr_st1 фиксирует data и взводит flag1
flag1 переводится в другой домен — flag1to2
flag1to2 обнаруживается автоматом pr_st2
автомат pr_st2 переходит в состояние s2 и фиксирует данные на выходе.
Т.е. есть как минимум два такта на прохождение данных от data к data_out.
Хотя для высоких частот это может быть стать проблемой.
Спасибо за указание на узкое место.
P.S. Но код Грея всё равно не спасёт. Или здесь я тоже не прав?
Автомат pr_st1 фиксирует data и взводит flag1
flag1 переводится в другой домен — flag1to2
flag1to2 обнаруживается автоматом pr_st2
автомат pr_st2 переходит в состояние s2 и фиксирует данные на выходе.
Т.е. есть как минимум два такта на прохождение данных от data к data_out.
Хотя для высоких частот это может быть стать проблемой.
Спасибо за указание на узкое место.
P.S. Но код Грея всё равно не спасёт. Или здесь я тоже не прав?
Хм… а по моему, при передаче кодом грея в метастабильном состоянии может оказаться только один бит, тот который в данный момент меняется. Остальные же изменились раньше и всегда верные.
Я не спорю как будет:) я знаю ответ:).
Код грея делает так что одно значение от другого будет отличаться ровно 1 битом. В любой момент времени вы можете получить либо новое, либо старое значение. Даже в случае мета-стабильности у вас в итоге триггер свалиться к новому или старому значению и это всегда даст правильный ответ.
Вам не нужно обеспечить чтобы счетчик фифо из одного домена в другом менялся последовательно, он может перепрыгивать через значение. Вам важно обеспечить чтобы вы из одного домена в другой из-за гонки не передали значение которого не было. А с кодом грея и полным счетчиком это возможно только если счетчик смениться несколько раз за врем фронта. Подчеркиваю фронта, а не периода.
Код грея делает так что одно значение от другого будет отличаться ровно 1 битом. В любой момент времени вы можете получить либо новое, либо старое значение. Даже в случае мета-стабильности у вас в итоге триггер свалиться к новому или старому значению и это всегда даст правильный ответ.
Вам не нужно обеспечить чтобы счетчик фифо из одного домена в другом менялся последовательно, он может перепрыгивать через значение. Вам важно обеспечить чтобы вы из одного домена в другой из-за гонки не передали значение которого не было. А с кодом грея и полным счетчиком это возможно только если счетчик смениться несколько раз за врем фронта. Подчеркиваю фронта, а не периода.
Это все правильно, но вовсе не так радужно в случае (крайне маловероятном, но в жизни всякое бывает), когда период изменения счетчика меньше чем возможная задержка сигнала по пути в другой тактовый домен (подразумевая, что по каждому биту задержки могут быть разными).
Ну то есть в реальной жизни я сомневаюсь что такое может приключиться, но о чем говорит коллега понятно.
Ну то есть в реальной жизни я сомневаюсь что такое может приключиться, но о чем говорит коллега понятно.
Это не верно.
Не важно сколько у вас идет сигнал из одного домена в другой и сколько раз за это время изменится счетчик. Важно только насколько расходиться шина, если у вас разница между приходами самого быстрого бита и самого медленного больше периода клока изменяющего счетчик то будет беда, но это как же надо развестись чтобы такое получилось:)
вот у вас есть счетчик который меняется
0 1 2 3 4 5 6 7 8 9 10
пусть он доходит в другой домен с задержкой в 2 такта
0 0 0 1 2 3 4 5 6 7 8 9
пусть другой домен выбирает каждый 10 отсчет
0 0 0 0 0 0 0 0 0 7 7 7 7…
но обратите внимание что когда мы меняли 0 на 7, мы на входе который защелкивает данные имели то 6 7 8, То есть мы могли защелкнуть 6, или переход 6-7 или 7 или переход 7-8, мы не могли видеть перехода 6 — 8, мы не могли видеть часть от 6 и часть от 7, так как считаем что период изменения больше разбежки шины.
так вот 6, 6-7, 7, 7-8, в коде Грея все эти ситуации будут превращены в 6 или 7 или 8, 6-7 и 7-8 свалиться в одно из устойчивых.
И не важно с какой частотой вы выбираете и с какой общей задержкой приходят данные
Не важно сколько у вас идет сигнал из одного домена в другой и сколько раз за это время изменится счетчик. Важно только насколько расходиться шина, если у вас разница между приходами самого быстрого бита и самого медленного больше периода клока изменяющего счетчик то будет беда, но это как же надо развестись чтобы такое получилось:)
вот у вас есть счетчик который меняется
0 1 2 3 4 5 6 7 8 9 10
пусть он доходит в другой домен с задержкой в 2 такта
0 0 0 1 2 3 4 5 6 7 8 9
пусть другой домен выбирает каждый 10 отсчет
0 0 0 0 0 0 0 0 0 7 7 7 7…
но обратите внимание что когда мы меняли 0 на 7, мы на входе который защелкивает данные имели то 6 7 8, То есть мы могли защелкнуть 6, или переход 6-7 или 7 или переход 7-8, мы не могли видеть перехода 6 — 8, мы не могли видеть часть от 6 и часть от 7, так как считаем что период изменения больше разбежки шины.
так вот 6, 6-7, 7, 7-8, в коде Грея все эти ситуации будут превращены в 6 или 7 или 8, 6-7 и 7-8 свалиться в одно из устойчивых.
И не важно с какой частотой вы выбираете и с какой общей задержкой приходят данные
Давайте рассмотрим такую ситацию: клок записи 250 МГц, клок чтения 100 МГц.
Задержки на шине передачи от от одного счётчика к другому распределились так:
bit0 — 1.1 ns
bit1 — 1.2 ns
bit2 — 1.4 ns
Это всё законно для частоты 250 МГц.
Теперь случай 1: фронт клока чтения отстал на 1.0 ns — все три бита получат старое значение
Следующий случай: фронт отстал на 1.3 ns — bit0 и bit1 — новое, bit 2 — старое
Ещё случай: фронт отстал ровно на 1.2 ns — bit2 — старое, bit0 — новое, bit1 — в метастабильном.
А эти случаи будут идти постоянно.
Задержки на шине передачи от от одного счётчика к другому распределились так:
bit0 — 1.1 ns
bit1 — 1.2 ns
bit2 — 1.4 ns
Это всё законно для частоты 250 МГц.
Теперь случай 1: фронт клока чтения отстал на 1.0 ns — все три бита получат старое значение
Следующий случай: фронт отстал на 1.3 ns — bit0 и bit1 — новое, bit 2 — старое
Ещё случай: фронт отстал ровно на 1.2 ns — bit2 — старое, bit0 — новое, bit1 — в метастабильном.
А эти случаи будут идти постоянно.
Отлично, теперь мы к этому добавляем кодирование кодом грея
старое значение {bit0, bit1, bit2} отличается от нового {bit0, bit1, bit2} только одним битом
то есть у нас 3 варианта
{bit0, bit1, bit2} -> {New, bit1, bit2}
{bit0, bit1, bit2} -> {bit0, New, bit2}
{bit0, bit1, bit2} -> {bit0, bit1, New}
для первого случая мы получим
{bit0, bit1, bit2} -> {bit0, bit1, bit2}
второго случая
{bit0, bit1, bit2} -> {New, bit1, bit2}
{bit0, bit1, bit2} -> {bit0, New, bit2}
{bit0, bit1, bit2} -> {bit0, bit1, bit2}
то есть 2 варианта изменились, а третий передался просто старым
для 3 случая
{bit0, bit1, bit2} -> {New, bit1, bit2}
{bit0, bit1, bit2} -> {bit0, New или bit1, bit2}
{bit0, bit1, bit2} -> {bit0, bit1, bit2}
то есть первый вариант прошел, второй вариант либо прошол либо остался старым
третий вариант остался старым
старое значение {bit0, bit1, bit2} отличается от нового {bit0, bit1, bit2} только одним битом
то есть у нас 3 варианта
{bit0, bit1, bit2} -> {New, bit1, bit2}
{bit0, bit1, bit2} -> {bit0, New, bit2}
{bit0, bit1, bit2} -> {bit0, bit1, New}
для первого случая мы получим
{bit0, bit1, bit2} -> {bit0, bit1, bit2}
второго случая
{bit0, bit1, bit2} -> {New, bit1, bit2}
{bit0, bit1, bit2} -> {bit0, New, bit2}
{bit0, bit1, bit2} -> {bit0, bit1, bit2}
то есть 2 варианта изменились, а третий передался просто старым
для 3 случая
{bit0, bit1, bit2} -> {New, bit1, bit2}
{bit0, bit1, bit2} -> {bit0, New или bit1, bit2}
{bit0, bit1, bit2} -> {bit0, bit1, bit2}
то есть первый вариант прошел, второй вариант либо прошол либо остался старым
третий вариант остался старым
Не так. Обратите внимание, что частота записи 250 МГц, а частота чтения 100 МГц. Т.е. новое значение изменилось больше чем на один бит.
сие невозможно:) разбежка между битами 0.3 нСек, а период задающего клока 4 нСек. Ни при каких условиях вы не можете на другом конце шины в один момент времени получить не соседние значения, которые отличаются не более чем на 1 бит.
то что шина в 100 МГц видит данные в 2.5 раза реже не означает что данные в шине пропадают в промежутки между клоками…
Постройте симуляцию и посмотрите.
то что шина в 100 МГц видит данные в 2.5 раза реже не означает что данные в шине пропадают в промежутки между клоками…
Постройте симуляцию и посмотрите.
Внимательно посмотрел и признаю — я не прав. Действительно год Грея можно использовать при переходе между тактовыми доменами.
Благодарю за советы.
Дальше можно обсудить будет ли реализация на коде Грея более эффективной.
Благодарю за советы.
Дальше можно обсудить будет ли реализация на коде Грея более эффективной.
есть ограничения: код Грея будет работать только для FIFO глубиной степени 2^n, иначе при переходе максимум-минимум будут многобитывае изменения.
второе ограничение: если вы хотите иметь флаги частичного заполнения, то вам придется сделать обратные преобразователи код Грея — обычный код, чтобы сравнивать уровни заполнения.
Пересинхронизация будет удобнее, но чуть объемнее. Надо все биты через 2 триггера пропускать, а не один флаг, с другйо стороны нет логики на флаге. Расширенный бит счетчика делает очень удобный анализ полно-пусто, без частичных уровней заполнения можно все сделать в коде Грея без обратного преобразования.
второе ограничение: если вы хотите иметь флаги частичного заполнения, то вам придется сделать обратные преобразователи код Грея — обычный код, чтобы сравнивать уровни заполнения.
Пересинхронизация будет удобнее, но чуть объемнее. Надо все биты через 2 триггера пропускать, а не один флаг, с другйо стороны нет логики на флаге. Расширенный бит счетчика делает очень удобный анализ полно-пусто, без частичных уровней заполнения можно все сделать в коде Грея без обратного преобразования.
Похоже код Грея мне не поможет. Настройка флагов обязательно нужна.
преобразователь в код грея и обратно — это небольшая комбинаторная схема. Скорее всего она имеет меньший или сравнимый размер с логикой формирования флагов синхронизации.
Внутри домена у вас нормальный счетчик адреса, в другой домен счетчик идет через преобразователь в код Грея, переходит в этом виде между доменами и на той стороне восстанавливается опять в нормальный вид. Так решено пожалуй 99% FIFO через которые делают пересинхронизацию. Это стандартное и облизанное со всех сторон решение.
Внутри домена у вас нормальный счетчик адреса, в другой домен счетчик идет через преобразователь в код Грея, переходит в этом виде между доменами и на той стороне восстанавливается опять в нормальный вид. Так решено пожалуй 99% FIFO через которые делают пересинхронизацию. Это стандартное и облизанное со всех сторон решение.
Счётчик Грея как раз и нужен для того, чтобы у Вас изменялся только 1 бит.
И тогда, очевидно, возможны только 2 ситуации:
1) Бит уже успел измениться (будет защёлкнуто новое значение счётчика)
2) Бит ещё не успел измениться (будет защёлкнуто предыдущее значение счётчика)
И тогда, очевидно, возможны только 2 ситуации:
1) Бит уже успел измениться (будет защёлкнуто новое значение счётчика)
2) Бит ещё не успел измениться (будет защёлкнуто предыдущее значение счётчика)
Я бы изменил название на «Как работает асинхронное FIFO» для ясности
Рекомендую ознакомиться http://www.zimmerdesignservices.com/mydownloads/no_mans_land_20130328.pdf В некоторых случаях с большим clock skew даже правильно написанное асихронное фифо не будет правильно работать без timing constraints
Это память типа «первым вошёл-первым ушёл» (first input – first output).
Вообще-то «first in — first out».
А почему вы у себя в коде пишете:
А если кому-то потребуется использовать ваше fifo в дизайне который работает на частоте больше 1 ГГц, оно нормально будет симулироваться?
flag2to1 <= flag2 after 1 ns when rising_edge( clk1 );
А если кому-то потребуется использовать ваше fifo в дизайне который работает на частоте больше 1 ГГц, оно нормально будет симулироваться?
Ну если на 1 ГГц то надо написать after 0.1 ns, или меньше.
Я всегда пишу after, так лучше видно сигналы на временной диаграмме и предохраняет от расхождения с работой в реальной аппаратуре.
Я всегда пишу after, так лучше видно сигналы на временной диаграмме и предохраняет от расхождения с работой в реальной аппаратуре.
Эти задержки накапливаются. Где-то в другом месте кто-то может написать еще одно присвоение, потом еще.
В общем весь продуктовый RTL который я видел был написан без задержек. Если хочется увидеть какие-то «мнимые» задержки на временной диаграмме, досточно просто включить отображение дельта-циклов.
В общем весь продуктовый RTL который я видел был написан без задержек. Если хочется увидеть какие-то «мнимые» задержки на временной диаграмме, досточно просто включить отображение дельта-циклов.
Мы пишем задержки только после синхронных присвоений под CLK, поэтому они не накапливаются. При следующем защелкивании — она снова будет 1нс. Про 1ГГц — верно подмечено, нужно весь код заменить на что-то типа 0.1нс. Поэтому я в своих проектах ввел переменную td, которой присваивается значение этой задержки.
«Мы» это стандарт на кодирование в компании или просто чья-то светлая идея?
Изначально — это «светлая идея», которая затем переросла в негласный стандарт компании.
К сожалению, он не всеми соблюдается, но мы стремимся к единообразию и соблюдению определенных правил написания кода. В свое время я написал такой документ, но сами понимаете — протащить его наверх и сделать это стандартом крайне непросто. Несмотря на то, что многие поддержали эту идею, а коллективные обсуждения по этому вопросу возникали неоднократно. :)
К сожалению, он не всеми соблюдается, но мы стремимся к единообразию и соблюдению определенных правил написания кода. В свое время я написал такой документ, но сами понимаете — протащить его наверх и сделать это стандартом крайне непросто. Несмотря на то, что многие поддержали эту идею, а коллективные обсуждения по этому вопросу возникали неоднократно. :)
Это всё на основе реального опыта. Было несколько случаев, когда результаты моделирования резко отличались от реальной работы. Разбор выявил узкое место. Это присваивание тактовых частот. Присваивание тактовых частот также производится с дельта-задержкой и это приводит к трудно обнаруживаемым проблемам. В итоге — проще написать aftger 1 ns.
Обычно для моделирования всяких clock-гейтов и прочей логики на клоках используются присвоения с immediate notification, тогда event скедулиться в текущий дельта-цикл. Не помню деталей VHDL, нужно спеку смотреть. Последнее время пользуюсь только SystemC.
В общем использование задержек в синтезируемом коде приводит к путтанице. Особенно если у вас в перемешку RTL с gate-level с timing аннотациями. В общем я за свою жизнь уже настродался с интеграцией кода вроде вашего, поэтому у меня на него больная реакция.
В общем использование задержек в синтезируемом коде приводит к путтанице. Особенно если у вас в перемешку RTL с gate-level с timing аннотациями. В общем я за свою жизнь уже настродался с интеграцией кода вроде вашего, поэтому у меня на него больная реакция.
Шёл 2017 год. Люди изобретали двухклоковое фифо, открывая попутно для себя свойства кода Грея, допуская ошибки связанные с метастабильностью в цепях сброса и пересечении клоковых доменов.
Clock domain crossing: http://www.sunburst-design.com/papers/CummingsSNUG2008Boston_CDC.pdf
Async fifo design: http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_FIFO1.pdf
Это не фундаментальные труды по схемотехнике и разработке цифровых схем, но дают представление о предмете.
И еще, боюсь показаться грубым или заносчивым, но скажите пожалуйста, что подвигает Вас писать статьи? Что решения описанные в этой, что в предыдущей статье содержат классические ошибки начинающих (начиная от неглубокой проработки теории и специфики задач и, вследствии, принятие и реализация несоответствующих схемных решений, щедро приправленых синдромом NIH). И все бы ничего, если бы это был студенческий энтузиазм, но в профиле ж написано «инженер-разработчик».
Clock domain crossing: http://www.sunburst-design.com/papers/CummingsSNUG2008Boston_CDC.pdf
Async fifo design: http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_FIFO1.pdf
Это не фундаментальные труды по схемотехнике и разработке цифровых схем, но дают представление о предмете.
И еще, боюсь показаться грубым или заносчивым, но скажите пожалуйста, что подвигает Вас писать статьи? Что решения описанные в этой, что в предыдущей статье содержат классические ошибки начинающих (начиная от неглубокой проработки теории и специфики задач и, вследствии, принятие и реализация несоответствующих схемных решений, щедро приправленых синдромом NIH). И все бы ничего, если бы это был студенческий энтузиазм, но в профиле ж написано «инженер-разработчик».
Век живи — век учись (правда всё равно не поможет)
При всех недостатках — у меня есть о чём рассказать и показать.
Хотя бы для организации дискуссии.
При всех недостатках — у меня есть о чём рассказать и показать.
Хотя бы для организации дискуссии.
Цитата: «Но что делать если что-то не устраивает в стандартных решениях? Ответ один – разобраться и написать самому». Дальше можно не читать! Если у нас начальники лаборатории такую ересь пишут, то тогда я понимаю почему Элон Маск за 7 лет поднимает сверхтяж, а в «Роскосмосе» за 20 лет не могут :(
Sign up to leave a comment.
Как работает FIFO