Как бы рабочее, как бы программистское
Jan. 6th, 2012 01:09 pmДумаю предлагать это на интервью людям, не знающим языков описания хардвера, но утверждающим, что смогут их быстро выучить.
Дан блок кода, состоящий из 4-х операторов присваивания:
X = A;
X <= B;
X <= X + 1;
X = D;
где "=" - обычное присваивание, а "<=" - "необычное". Известно, что после выполнения этого блока значение X равно A+1. Что можно сказать о семантике "необычного" присваивания?
no subject
Date: 2012-01-06 09:20 pm (UTC)no subject
Date: 2012-01-06 09:26 pm (UTC)no subject
Date: 2012-01-07 05:37 am (UTC)no subject
Date: 2012-01-07 08:34 am (UTC)no subject
Date: 2012-01-07 09:35 am (UTC)То есть, возвращаясь к началу поста, на интервью пальцы погнуть можно, но совсем быстро - не получиться.
no subject
Date: 2012-01-06 09:26 pm (UTC)no subject
Date: 2012-01-06 09:28 pm (UTC)no subject
Date: 2012-01-07 01:48 pm (UTC)то что вы видете как X <= X + 1
реально 2 команды (как минимум)- сделать инкремент и занести результат.
мне сложно тут рисовть таблицу но так это работает
no subject
Date: 2012-01-06 09:31 pm (UTC)no subject
Date: 2012-01-06 09:36 pm (UTC)no subject
Date: 2012-01-06 09:38 pm (UTC)no subject
Date: 2012-01-06 09:39 pm (UTC)no subject
Date: 2012-01-06 09:40 pm (UTC)no subject
Date: 2012-01-06 09:41 pm (UTC)no subject
Date: 2012-01-06 09:40 pm (UTC)no subject
Date: 2012-01-06 09:43 pm (UTC)no subject
Date: 2012-01-06 09:37 pm (UTC)X <= Y;
Y <= X;
no subject
Date: 2012-01-06 09:39 pm (UTC)no subject
Date: 2012-01-06 09:53 pm (UTC)no subject
Date: 2012-01-06 10:08 pm (UTC)no subject
Date: 2012-01-06 10:05 pm (UTC)2) Тогда я не понимаю, как может работать просто "=". "<=" подразумевает регистры, содержащие триггеры (flip-flops) с двухступенчатой синхронизацией. Т.е. если мы пишем
X <= Y
Y <= X
то оно подразумевает, что данные запишутся по одному фронту сигнала синхронизации в первую ступень триггера, а по другому - перепишутся и во вторую, и соответственно проникнут на выход. Никаких гонок, все синхронно. Соответственно, получется, что "=" пишет прямо во вторую ступень, или в обе сразу? Но разве так бывает, и какой в этом начинании смысл? Ну, то есть смысл я могу усмотреть - остается больше (потенциально. вдвое больше) времени на вычисление логики. Но разве так действительно делают, что один и тот же триггер может работать в обоих режимах?
3) Все равно непонятно, почему результатом будет A+1, а не какая-то каша и не D.
4) При таком раскладе именно "<=" - обычное присваивание, а "=" - необычное.
no subject
Date: 2012-01-06 10:19 pm (UTC)2) Это уже мышление в терминах register transfer logic, а язык позволяет и более абстрактный behavioral level, на котором можно написать и синтезируемую логику в процедурном стиле, и совершенно несинтезируемые конструкции.
3) Потому что блок выше, согласно современному стандарту языка, эквивалентен
X = A;
tmp_X = B;
tmp_X = X + 1;
X = D;
// дожидаемся завершения всех активных в данный момент блоков
X = tmp_Х;
4) Обычное - для программистов, не знающих Верилога.
no subject
Date: 2012-01-06 11:34 pm (UTC)3) С другой стороны, при таком подходе можно сказать, что tmp_X - это у нас первая ступень двухступенчатого регистра, а собственно X - вторая. И если его синтезировать из индивидуальных элементов, совсем ничто не мешает так делать, и даже экономия выходит на том, что во многих случаях можно обходиться одноступенчатыми регистрами.
Кстати, исходя из чувствительностей, будет ли оно побито на такты вот так?
X = A;
tmp_X = B;
---
tmp_X = X + 1;
X = D;
---
X = tmp_Х;
4) Но ведь получается, что X=X+1 не имеет смысла, а X <= X+1 - имеет, то есть именно <= более привычно для обычных программистов. Или оно само умеет отслеживать циклическую зависимость в X=X+1 и вставлять tmp_X?
no subject
Date: 2012-01-07 01:34 am (UTC)"blocking" and "non-blocking". Немало статей и книг посвящено пояснению как это все работает.
2. Как не очень програмист, но ЕЕ занимавшийся вериложеством скажу что считается очень дурным тоном мешать в одном блоке одни присвоения с другими.
3. На уровне RTL следует помнить что кроме двухступенчатых регистров есть еще transparent latches.
no subject
Date: 2012-01-07 02:03 am (UTC)3) Если это написано в одном блоке, то будет выполнено за один цикл симуляции. Разбиение на такты - забота программиста. Более того, что получится из блока - комбинаторная логика, двухступенчатые регистры или задвижки (latches), зависит от объявленной чувствительности блока (которую я для простоты опустил) и/или от наличия у переменных, изменяемых в блоке, live ranges, пересекающих начало блока. В данном случае синтезатор увидит, что значение Х всегда равно A+1, т.е. это будет или комбинаторный инкрементор, или регистр с инкрементором на входе в зависимости от объявленной чувствительности блока (по фронту клока или по уровню данных).
4) Для вспомогательных переменных, которые используются только внутри одного последовательно выполняемого блока, X=X+1 имеет конкретный смысл изменения значения индуктивной переменной. Как же еще циклы писать?
Для переменных с "реальным физическим смыслом", используемых в разных параллельно выполняемых блоках, имеет смысл писать <=, чтобы гарантировать независимость результатов софтверной симуляции от порядка исполнения блоков на последовательной машине. А синтезатор смотрит на блоки по отдельности, поэтому что А=В, что А<=B при чувствительности по уровню данных ("always @(B)") будет буфер, а по фронту клока ("always @(posedge clk)") - регистр.
А если написать X<=X+1 с чувствительностью по уровню, то "что видишь, то и поимеешь" - будет комбинаторный цикл, никакого волшебства.
no subject
Date: 2012-01-07 04:24 am (UTC)3) Но в итоге-то увеличенное значение должно попасть назад в X?
4) Я правильно понимаю, что X до присваивания и X после присваивания X=X+1 будут разными физическими регистрами, а потом переложится назад когда пойдет следующая итерация цикла? Потому что если это сделать в одном одноступенчатом регистре, то выйдет гонка с неопределенным результатом.
no subject
Date: 2012-01-07 06:42 am (UTC)Нанятно что верилог придуман для симуляции (равно как и VHDL) а использование для синтеза пришло потом. Так что не удивительно что бывает несинтезируемый код. В отличие от програм, которые всегда выполняемы, даже если результат - core dump.
no subject
Date: 2012-01-07 02:04 pm (UTC)no subject
Date: 2012-01-07 09:01 am (UTC)3,4) Если грубо, то перед синтезом сначала строится static single assignment graph блока (с разворачиванием циклов со статическими границами и прочими статическими оптимизациями), который для X<=A+1 и X=A; X=X+1 получится один и тот же.
Из блока получается кусок схемы, входами которого служат значения переменных, используемых как r-values до присваивания, а выходами - все переменные, которые бывали l-values. Если у блока была попрошена чувствительность по фронту клока, то к выходным переменным присобачиваются двухступенчатые регистры (flip-flops).
Если не было, то для каждой выходной переменной анализируется условие, при котором она может изменить значение. Если это условие не тождественная истина, то делается одноступенчатый регистр с защелкой, управляемой этим условием, иначе будет просто комбинаторная логика. При этом могут получиться комбинаторные циклы, и синтезатор о них может предупредить, но в общем случае он не в состоянии это определить (например, если цикл пересекает границы раздельно синтезируемых модулей), и этим занимаются утилиты "дальше по течению".
Так что если написать просто X=X+1 или X <= X+1 в качестве единственного оператора в блоке без клока, то получится без всяких регистров (потому что Х изменяет значение безусловно, а клока не попросили) инкрементор, замкнутый сам на себя. Это физического смысла не имеет, но Верилог - он как Си. Их девиз "вы этого хотели - вот вам".
no subject
Date: 2012-01-07 02:09 pm (UTC)И оно же небось время исполнения комбинаторной логики должно тоже анализировать? А то если ее сильно много, то она в такт не уложится.
no subject
Date: 2012-01-07 06:12 pm (UTC)А там где она читается, оно анализирует, из какого кода могло выполнение сюда прийти и использует соответствующий из них?
Именно так. Например, если было написано
x = a + b; if (cond) x = с + d;
то т.к. мы в зависимости от cond можем прийти к концу блока по двум разным путям, в результате для х получится мультиплексор с (безымянными) входами от a+b и с+d и селектором cond.
no subject
Date: 2012-01-07 06:15 pm (UTC)Для timing analysis есть отдельные утилиты. Это не проблема синтезатора, так же как не проблема компилятора с языка программирования предупреждать программиста о неэффективном алгоритме.
no subject
Date: 2012-01-08 02:53 pm (UTC)no subject
Date: 2012-01-06 09:35 pm (UTC)no subject
Date: 2012-01-06 09:39 pm (UTC)no subject
Date: 2012-01-06 10:31 pm (UTC)X=A;
X:=X+1;
X=D;
После его выполнения А получается на единицу меньше чем D. В чём семантика значков "=" и ":=" ?
no subject
Date: 2012-01-06 10:41 pm (UTC)Стандартная семантика присваивания для = и := удовлетворяет такой формулировке.В интерфейсе ЖЖ не хватает фичи оповещения о редактировании комментария в процессе написания ответа на него. "=" - ребро между узлом типа "значение" и узлом типа "функция", ":=" - определение функции в узле. Так годится?
no subject
Date: 2012-01-06 10:48 pm (UTC)no subject
Date: 2012-01-06 10:49 pm (UTC)no subject
Date: 2012-01-06 10:59 pm (UTC)no subject
Date: 2012-01-06 11:12 pm (UTC)no subject
Date: 2012-01-07 12:42 am (UTC)no subject
Date: 2012-01-07 08:46 am (UTC)no subject
Date: 2012-01-07 01:15 am (UTC)X := old Y;
Y := old X
http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=00130079
no subject
Date: 2012-01-07 01:31 am (UTC)no subject
Date: 2012-01-07 02:40 am (UTC)no subject
Date: 2012-01-07 02:52 am (UTC)терпентинмайкрософт на что-нибудь полезен!no subject
Date: 2012-01-07 09:58 am (UTC)Даже если предположить, что одно из присваиваний подразумевает onclock, а другое -- просто alias (соединение проводников), всё равно непонянто, почему не будет ошибки типа multisource. Даже если на разных "=>" разные клоки, будет либо явно multisource, либо мусорное значение в результате.
no subject
Date: 2012-01-07 06:04 pm (UTC)Фокус в том, что ни одно из присваиваний ничего само по себе не подразумевает. Наличие и тип регистра для переменной выводится из data flow graph, построенного из блока(плюс еще некоторые синтаксические тонкости, но это детали).
почему не будет ошибки типа multisource
Потому что все эти присваивания - внутри одного блока. Один блок - один source.