web-dev-qa-db-fra.com

Comment interpréter les affectations bloquantes ou non bloquantes dans Verilog?

Je suis un peu confus quant à la façon dont les affectations bloquantes et non bloquantes sont interprétées lors de la création d'un diagramme matériel. Faut-il en déduire qu'une cession non bloquante nous donne un registre? Ensuite, selon cette déclaration c <= a+b, c serait un registre correct, 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
23
infinitloop

Il est certainement un peu difficile de comprendre les différences entre les affectations bloquantes et non bloquantes. Mais pas de peur - il existe une règle pratique:

Si vous souhaitez déduire une logique de liste déroulante avec un bloc always, utilisez des affectations bloquantes (=). Si vous voulez une logique séquentielle, utilisez un bloc always 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 savoir quelle structure additionneur/bascule vous essayez de construire, vous risquez de créer des chemins de retour combo (qui sont mauvais). Et comme vous n'avez pas de bus d'entrée, vous essayez essentiellement de construire a, b & c à partir de rien!

Mais pour répondre à votre question, toute variable affectée à un bloc always cadencé déduira une bascule, sauf si elle est affectée à l'aide de 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

L'une des principales raisons de suivre la règle empirique et de ne pas mélanger les affectations bloquantes et non bloquantes dans un bloc always est que le mélange de vos affectations peut entraîner de graves incohérences de simulation entre les simulations RTL et les opérations matérielles gate-sims/real. Le simulateur Verilog traite = et <= de manière très différente. Les affectations bloquantes signifient "attribuer immédiatement la valeur à la variable à l'instant". Les affectations non bloquantes signifient «déterminez quoi attribuer à cette variable et stockez-la pour l'affecter ultérieurement». Un bon article à lire pour mieux comprendre ceci est: Voir aussi: http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf

27
Marty

La sagesse conventionnelle de Verilog a tout faux. L'utilisation d'attributions de blocage pour une variable locale ne pose aucun problème. Cependant, vous ne devez jamais utiliser d'assignations bloquantes pour la communication synchrone, car elles ne sont pas déterministes.

Une affectation non bloquante dans un bloc toujours synchronisé induira toujours une bascule, comme dicté par la sémantique.

Qu'une affectation de blocage dans un bloc horodaté implique toujours une bascule ou non dépend entièrement de son utilisation. S'il est possible que la variable soit lue avant d'être affectée, une bascule sera déduite. Sinon, cela ressemble à une variable temporaire et il en résulte une certaine logique combinatoire.

42
Jan Decaluwe

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 s'il a tout à fait raison. Mélanger des déclarations bloquantes et non bloquantes est maintenant un tabou, grâce à Mr. Cummings.

Le problème est que la plupart des sites é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 seul endroit où j'ai trouvé le style de codage mentionné par Jan est le code gagnant de cet article . Et cela, je suis tombé par hasard 

2
Akaberto

J'ai eu du mal à ça aussi.

Mais tout d’abord, vous devez comprendre que ne pas bloquer ou bloquer n’a en réalité rien à voir avec la création ou non d’un verrou/ff! 

Pour leur différence, vous pouvez le comprendre simplement (au début) par ce point: i. Si vous utilisez le blocage, les phrases suivantes ne pourront pas être exécutées avant la valeur attribuée à la phrase LHS de la phrase bloquée, car ce qui a été modifié en LHS pourrait être mis à jour et utilisé si la variable était utilisée. Cependant, pour le non-blocage, il ne bloque pas la phrase suivante, comme parallèle à la phrase suivante (en fait, le calcul RHS devrait être effectué en premier, mais cela n'a pas d'importance, ignorez-le lorsque vous confondez). Le LHS ne change pas/n'est pas mis à jour pour l'exécution de cette heure (mis à jour la prochaine fois quand le blocage est déclenché à nouveau). Et la phrase suivante utilise l'ancienne valeur, telle qu'elle se mettait à 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é consiste à déterminer si, dans votre code (toujours en mode bloc), il existe des variables de cas non associées à une valeur, mais pouvant se produire. Si vous ne lui transmettez pas de valeur et que cela 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. 

Après pourrait également créer un verrou/ff:

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

-> latch/ffs créés pour in = 1, b aucune affectation, in = 0 a aucune affectation. 

De plus, lorsque vous sentez que la fonction clk always @(posedge clk) est posée, elle se termine forcément par latch/ff. Parce que, pour clk, il doit exister un bord négatif, et que vous ne faites rien, latch/ffs sont créés pour conserver toute l'ancienne valeur!

1
Steve

Je peux répondre à votre question, mais je pense qu'un document serait préférable pour cela. Je vous recommande donc de lire ce document de Clifford Cummings. Il dissipera tous vos doutes et, en plus, renforcera votre compréhension de Verilog.

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

0
Karan Shah

s'il vous plait, vous pouvez toujours interpréter le verilog dans le domaine numérique, il vous suffit de comprendre ce qui se passera si le même code que vous avez écrit sera converti au niveau de la porte; , cela limitera votre réflexion. 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 ne voulez que cela 

  1. d'abord l'additionneur complet sera fait - les entrées a et b
    1. la sortie ira sur une bascule créant une sortie ayant une synchronisation avec clk
    2. maintenant, puisque l'assignation bloque, le nouveau a sera ensuite appliqué au prochain ajout complet ayant ce nouveau a et c en entrée, sa sortie ira à dffcsync pour créer un nouveau b
    3. maintenant puisque b = c + a; est-il qui bloque l'état, donc b est mis à jour pour ce nouveau b
    4. maintenant son c <= a + b maintenant ce qui se passe est un additionneur complet est créé avec a et b comme entrée qui va à dff sync to clk, maintenant il y aurait une autre condition comme à nouveau dire a = c;
    5. alors un dff sera créé en ayant l’ancien c et non le nouveau créé par l’instruction non bloquante et la sortie de ce dff synchronisé avec clk ira à a et sera mise à jour

merci salutations Rahul jain

0
Rahul Jain