Comment interpréter les affectations bloquantes vs non bloquantes dans Verilog?
Je suis un peu confus sur la façon dont les affectations bloquantes et non bloquantes sont interprétées quand il s'agit de dessiner un diagramme matériel. Devons-nous déduire qu'une affectation non bloquante nous donne un registre? Ensuite, selon cette Déclaration c <= a+b
, c serait un droit de registre, mais pas a et 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 réponses
Il est certainement un peu difficile de comprendre les différences entre les affectations bloquantes et non bloquantes au départ. Mais pas de peur-il y a une règle pratique de base:
Si vous voulez déduire une logique combo avec un bloc
always
, utilisez des affectations de blocage (=
). Si vous voulez une logique séquentielle, utilisez un blocalways
cadencé avec des affectations non bloquantes (<=
). Et essayez de ne pas mélanger les deux.
Votre code ci-dessus n'est probablement pas le meilleur exemple. Sans le savoir quelle structure additionneur / flipflop vous essayiez de construire, il y a le danger d'avoir des chemins de rétroaction combo (qui sont mauvais). Et puisque vous n'avez pas de bus d'entrée, vous essayez essentiellement de construire a
, b
& c
hors de l'air mince!
Mais pour répondre à votre question, toute variable assignée à un bloc always
cadencé infèrera un flipflop, sauf si elle est assignée en utilisant l'opérateur de blocage (=
) et utilisée comme une sorte de variable locale.
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
Une grande raison de suivre le règle de base et ne pas mélanger les affectations bloquantes et non bloquantes dans un bloc always
, est que le mélange de vos affectations peut provoquer de graves discordances de simulation entre les sims RTL et les Sims / opérations matérielles réelles. Le simulateur verilog traite =
et <=
différemment. Les affectations bloquantes signifient "assigner la valeur à la variable immédiatement cet instant". Les affectations non bloquantes signifient "déterminer ce qu'il faut attribuer à cette variable et le stocker pour l'assigner à un moment futur". Bon papier à lire pour mieux comprendre cela est: Voir Aussi: http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf
La sagesse conventionnelle de Verilog a tout faux. Il n'y a pas de problème avec l'utilisation des affectations de blocage pour une variable local. Cependant, vous ne devriez jamais utiliser des affectations de blocage pour la communication synchrone, car cela n'est pas déterministe.
Une affectation non bloquante dans un bloc toujours cadencé déduira toujours une bascule, comme dictée par la sémantique.
Si une affectation de blocage dans un bloc toujours cadencé infère une bascule ou non dépend entièrement de la façon dont il est utilisé. S'il est possible que la variable soit lue avant d'être assignée, une bascule sera déduite. Sinon, c'est comme une variable temporaire et cela entraînera une logique combinatoire.
Je veux juste ajouter à la réponse de Jan Decaluwe. Il semble qu'il y ait très peu de code dans la nature qui utilise réellement ce que décrit Jan Decaluwe, même si c'est absolument juste. Mélanger des déclarations bloquantes et non bloquantes est maintenant un tabou, grâce à M. Cummings.
Le problème est, la plupart des endroits évitent d'utiliser des instructions de blocage pour les variables locales et il y a très peu de code dans L'espace de recherche immédiat de Google qui donne un exemple de la façon dont cela est fait. Le le seul endroit où j'ai trouvé le style de codage mentionné par Jan est le code gagnant dans cet article . Et ça, je suis tombé accidentellement
J'ai eu un moment difficile à ce sujet aussi.
Mais tout d'abord, vous devez comprendre que le non-blocage ou le blocage n'a rien à voir avec la création d'un latch/ff!
Pour leur différence, vous pouvez le comprendre simplement (au début) par ce point: I. Si utiliser le blocage, les phrases après ne peuvent pas être exécutées jusqu'à ce que la phrase de bloc LHS assignée Valeur, puisque ce qui a changé en LHS de celui-ci pourrait être mis à jour et utilisé si la variable est utilisée. Cependant, pour non-blocage, il ne le fait pas bloquer la phrase suivante comme parallèle avec la phrase suivante(en fait le calcul RHS devrait être fait en premier, mais peu importe, ignorez-le quand vous confondez). Le LHS ne change pas / mis à jour pour l'exécution de cette fois (mis à jour la prochaine fois lorsque le bloc est toujours déclenché à nouveau). Et la phrase suivante utilise l'ancienne valeur, telle qu'elle est mise à jour à la fin du cycle d'exécution.
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;
Un point clé est de trouver si dans votre code (toujours bloquer) il y a une variable de cas non assignée mais qui pourrait arriver. Si vous ne lui passez pas de valeur et que ce cas se produit, latch / ff est créé pour conserver la valeur.
Par exemple
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.
Suivant pourrait également créer latch / ff:
always @(*) begin
if(in) a = 1;
else b = 1;
end
-- > latch / ffs créé pour in = 1, B pas d'affectation, in = 0 a pas d'affectation.
De plus, lorsque vous détectez posedge de clk always @(posedge clk)
, il est lié à se terminer par latch / ff. Parce que, pour clk, il doit exister un bord négatif, et vous ne faites rien, latch / ffs sont créés pour garder toute l'ancienne valeur!
S'il vous plait , vous pouvez toujours interpréter le verilog dans le domaine numérique juste vous devez comprendre ce qui se passera si le même code que vous avez écrit sera converti au niveau de la porte , personnellement, je ne vais pas par la règle que d'utiliser non bloquant dans seq ou utiliser le blocage en combinatoire, cela limitera votre pensée . s'en tenir au côté numérique du code seulement voici ce qui se passera si votre code est converti au niveau de la porte il suffit de voir que vous le voulez seulement
- tout d'abord, l'additionneur complet sera fait -- les entrées a et b
- sortie ira à flip flop créer une sortie ayant une synchronisation avec clk
- maintenant, puisque l'affectation est bloquante, le nouveau a sera ensuite appliqué au prochain ajout complet Ayant ce nouveau a et c en entrée , la sortie ira à dffcsync pour clk créant un nouveau b
- maintenant depuis b = c + a; y a-t-il qui bloque statment donc b est mis à jour vers ce nouveau b
- maintenant son c
- alors un dff sera créé ayant l'ancien c pas le nouveau juste créé par l'instruction non bloquante et la sortie de cette synchronisation dff à clk va à a et a est mis à jour
Merci égard Rahul jain
Je peux répondre à votre question, mais je pense qu'un article serait le mieux pour cela, donc je vous recommande de lire ce document de Clifford Cummings. Il effacera tous vos doutes et en plus de cela renforcera votre compréhension de verilog.
Http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA_rev1_2.pdf