Как интерпретировать блокирование и неблокирующие назначения в Verilog?

Я немного смущен тем, как блокирующие и неблокирующие назначения интерпретируются, когда дело доходит до рисования аппаратной диаграммы. Должны ли мы сделать вывод, что неблокирующее назначение дает нам реестр? Тогда согласно этому утверждению c <= a+b , c будет регистром справа, но не a и b?

module add (input logic clock,  
output logic[7:0] f);   

logic[7:0] a, b, c;  

always_ff @(posedge clock)  
begin   
  a = b + c;   
  b = c + a;   
  c <= a + b;  
end   

assign f = c;  

endmodule

6 ответов


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

если вы хотите вывести логику комбо с always блокировать, использовать назначения блокировки (=). Если вы хотите последовательную логику, используйте clocked always блок с неблокирующие назначения (<=). И постарайся не смешивать их.

ваш код выше, вероятно, не лучший образец. Не зная, какую структуру сумматора/flipflop вы пытались построить, существует опасность наличия комбинированных путей обратной связи (которые плохи). И поскольку у вас нет входных шин, вы по существу пытаетесь построить a, b & c из воздуха!

но чтобы ответить на ваш вопрос, любая переменная, назначенная в рамках накрутил always блок выведет flipflop, если он не назначен с помощью оператора блокировки (=) и используется как своего рода локальный переменная.

module add
  (
   input clock,
   input [7:0] in1,
   input [7:0] in2,
   output logic [7:0] f1, f2, f3, f4, f5
   );   


   // f1 will be a flipflop
   always_ff @(posedge clock) begin
      f1 = in1 + in2;
   end


   // f2 will be a flipflop
   always_ff @(posedge clock) begin
      f2 <= in1 + in2;
   end


   // f3 will be a flipflop
   // c1 will be a flipflop
   logic [7:0] c1;
   always_ff @(posedge clock) begin
      c1 <= in1 + in2;
      f3 <= c1 + in1;
   end


   // f4 will be a flipflop
   // c2 is used only within the always block and so is treated
   // as a tmp variable and won't be inferred as a flipflop
   logic [7:0] c2;
   always_ff @(posedge clock) begin
      c2 = in1 + in2;
      f4 = c2 + in1;
   end


   // c3 will be a flipflop, as it's used outside the always block
   logic [7:0] c3;
   always_ff @(posedge clock) begin
      c3 = in1 + in2;
   end

   assign f5 = c3 + in1;

endmodule

большая причина для следования эмпирическому правилу и не смешивания блокирующих и неблокирующих назначений в always блок, это то, что смешивание ваших заданий может вызвать серьезные несоответствия моделирования между RTL sims и gate-sims / реальной аппаратной работой. Симулятор verilog лечит = и <= совсем по-другому. Блокирование назначений означает "назначить значение переменной прямо сейчас". Неблокирующие назначения означают " выяснить, что назначьте этой переменной и сохраните ее, чтобы назначить в будущем". Хороший документ для чтения, чтобы лучше понять это: также см.:http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf


традиционная мудрость Verilog имеет все это неправильно. Нет проблем с использованием блокирующих назначений для A local переменной. Однако никогда не следует использовать назначения блокировки для синхронной связи, так как это недетерминировано.

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

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


просто хочу добавить к ответу Яна Декалуве. Кажется, что в дикой природе очень мало кода, который действительно использует то, что описывает Ян Декалуве, хотя это абсолютно правильно. Смешивание блокирующих и неблокирующих заявлений теперь табу, благодаря г-ну Каммингсу.

проблема в том, что большинство мест избегают использования операторов блокировки для локальных переменных, и в непосредственном пространстве поиска Google очень мало кода, который выглядит как пример того, как это делается. Единственное место, где я нашел стиль кодирования, как отметил Ян выигрышный код в этой статье. И на это я наткнулся случайно


мне тоже пришлось нелегко.

но во-первых, вы должны понимать, что неблокирование или блокировка на самом деле не имеет ничего общего с тем, будет ли создана защелка/ff!

для их разницы вы могли бы понять это просто(в начале) к этому моменту: я. Если использовать блокировку, предложения после нее не могут быть выполнены до тех пор, пока не будет присвоено значение LHS, поскольку то, что изменилось на LHS, может быть обновлено и использовано, если используется переменная. Однако, для неблокирующий, он не блокирует следующее предложение, как параллельное следующему предложению(на самом деле расчет RHS должен быть сделан первым, но это не имеет значения, игнорируйте его, когда вы путаете). LHS не изменяется / обновляется для выполнения этого времени (обновляется в следующий раз, когда всегда блокируется снова). И следующее предложение использует старое значение, поскольку оно обновляется в конце цикла выполнения.

a = 0; b= 0;
a = 1;
b = a;
--> output a = 1, b = 1;
a = 0; b= 0;
a <= 1;
b = a;
--> output a = 1, b = 0;

один ключевой момент-найти, есть ли в вашем коде (всегда блок) какая-либо переменная case не назначенное значение, но может произойти. Если вы не передадите ему значение, и это произойдет, то latch / ff будет создан, чтобы сохранить значение.

например,

always @(*) begin
    if(in) out = 1;
    else out = 0;
end
--> this end without latch/ff
always @(*) begin
    if(in) out = 1;
end
--> this end with one latch/ff to keep value when in = 0, as it might happen and you didn't assign value to out as in=1 do. 

следующее также может создать защелку / ff:

always @(*) begin
    if(in) a = 1;
    else b = 1;
end

--> защелка / ffs создана для in=1, b нет назначения, in=0 a нет назначения.

кроме того, когда вы чувствуете posedge clk always @(posedge clk), он обязательно заканчивается защелкой / ff. Потому что для clk должен существовать отрицательный край, а вы этого не делаете что угодно, latch/ffs созданы, чтобы сохранить все старое значение!


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

  1. первый полный сумматор wiil будет сделано -- входы a и b
    1. выход пойдет на флип-флоп, создавая выход, имеющий синхронизацию с clk
    2. Теперь, поскольку назначение блокируется, поэтому новый a будет применен к следующему полному добавлению, имеющему этот новый a и c в качестве входа , выход его перейдет в dffcsync для clk создания нового b
    3. Теперь, поскольку b = c + a; есть ли блокирующее состояние, поэтому b обновляется до этого нового b
    4. Теперь его c
    5. тогда будет создан dff, имеющий старый c, а не новый, только что созданный оператором non blocking, и вывод этой синхронизации dff в clk переходит к a, и A обновляется

спасибо с уважением Рахул Джайн!--1-->


Я могу ответить на ваш вопрос, но я думаю, что одна статья будет лучше для этого, поэтому я рекомендую вам прочитать эту статью Клиффорда Каммингса. Это очистит все ваши сомнения и в дополнение к этому укрепит ваше понимание verilog.

http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA_rev1_2.pdf