Erzeugen Sie Flip-Flops nur mit kombinatorischer Logik

Nur zum Spaß wollte ich D-Typ-Flip-Flops nur mit kombinatorischer Logik in Verilog (oder SystemVerilog) entwerfen und simulieren . Ich verwende Verilator für die Simulation.

Mein erster Versuch, der ein klassisches Sechs-NAND-Design verwendet, scheint gut zu funktionieren – und hat alle Tests bestanden. Mein zweiter Versuch, basierend auf einem Vier-NAND-JK-Typ, funktioniert nicht. Der Ausgang bleibt während des positiven Taktpegels nicht verriegelt, und bei einigen Tests konvergiert die Simulation nicht einmal.

F: Ich weiß, dass es nicht normal oder optimal ist, aber ist es vernünftig , Flip-Flops mit kombinatorischer Logik in Verilog zu entwerfen? Wenn ja, stimmt etwas mit meinem zweiten Design nicht?

Dieser funktioniert:

module dff( input clk, input D, output Q );

   wire a, sn, rn, b, Qn;

always_comb // captures D @( posedge clk )
   begin
   a = !(b&sn);
   sn = !(a&clk);
   rn = !(sn&b&clk);
   b = !(rn&D);
   Q = !(sn&Qn);
   Qn = !(rn&Q);
   end

endmodule

Dieser funktioniert nicht:

module dff( input clk, input D, output Q );

   wire J=D, K=!D;
   wire sn, rn, qn;

always_comb // captures D @( posedge clk ), but fails to hold
   begin
   sn = !(J&clk&qn);
   rn = !(K&clk&Q);
   Q  = !(sn&qn);
   qn = !(rn&Q);
   end

endmodule

In dem Bemühen, Sperrzuweisungs- und Empfindlichkeitslisten zu eliminieren , habe ich den JK-basierten Ansatz wie folgt neu implementiert, aber die Ausgangswellenformen waren von diesem Unterschied nicht betroffen.

module dff( input clk, input D, output Q );

   wire J=D, K=!D;
   wire sn, rn, qn;

   assign sn = !(J&clk&qn);
   assign rn = !(K&clk&Q);
   assign Q  = !(sn&qn);
   assign qn = !(rn&Q);

endmodule

Hinweis: Ich habe das Design dieser auf den Beschreibungen und Diagrammen hier basiert .

Sie können HDLs verwenden, um dies zu tun, aber das macht nur für ASICs Sinn. FPGAs haben nicht die richtigen Verzögerungseigenschaften, um beim Aufbau sequentieller Schaltungen mit kombinatorischen Rückkopplungspfaden nützlich zu sein.

Antworten (2)

Der JK, den Sie haben, ist ein Latch, kein Flankentrigger. Es fehlt auch Feedback zwischen Q und qn (Ihrem ersten Code fehlt auch dieses Feedback). Combinational blockiert die Arbeit immer basierend auf der Vertraulichkeitsliste. Die Liste für die automatische Empfindlichkeit von always @*und always_comb` wird durch Signale bestimmt, die auf der rechten Seite eines Ausdrucks und nicht auf der linken Seite verwendet werden.

Wenn Sie die Empfindlichkeitsliste deklarieren, sollte es funktionieren: always @( J,K,clk, Q,qn )Auf diese Weise lösen Q und qn den Always-Block erneut aus.

Ein weiterer Ansatz ist die Use-Case-Anweisung:

always_comb
  if (clk)
    Q = Qpre;
  else
    case({J,K})
    2'b10 : Qpre = 1'b1;
    2'b01 : Qpre = 1'b0;
    2'd11 : Qpre = ~Q;
    default : Qpre = Qpre; // no change
    endcase

Das Problem bei der Verwendung von kombinatorischer Logik für Flops ist, dass es zu Haltezeitverletzungen kommen kann. Verilog ein unbestimmter Simulator. Das bedeutet, dass die Reihenfolge, in der ein Always-Block ausgewertet wird, nicht garantiert ist. Verwenden Sie den folgenden Code als Beispiel. Verilog kann b_combffvorher ausgeführt werden c_combff, daher cwird ihm der Wert von zugewiesen a. Dies liegt daran, dass wir blockierende Zuweisungen verwenden. Der Simulator könnte auch c_combffvorher laufen b_combffund wir bekommen den richtigen Wert. Beide Szenarien sind legal.

dff b_combff(.Q(b), .clk(clk), .D(a);
dff c_combff(.Q(c), .clk(clk), .D(b);

Eine gut platzierte nicht blockierende Zuweisung ( <=) auf Q kann helfen. Dadurch werden die Auswertung und die Aktualisierung in separate Regionen des Planers getrennt. Dies behebt die Hold-Time-Race-Bedingung, hilft aber nicht bei der Synthese.

Moderne Synthesizer sind smart, aber nicht brillant. Sie suchen nach Codierungsmustern, um zu bestimmen, wie RTL in äquivalente Gates konvertiert werden kann. Wenn sie always @es sehen, werden kantenempfindliche Flip-Flops hergestellt. Sie eignen sich gut für sehr einfache SR-, RS- und D-Verriegelungen. Biond, dass sie versuchen, kombinatorische Logik zu machen. Wenn Sie Ihre eigenen benutzerdefinierten Flops hinzufügen, versucht der Synthesizer, sie mit der bereits bekannten Logik abzugleichen, was höchstwahrscheinlich zu einer asynchronen Verriegelungslogik führt.

Kurz gesagt, es ist möglich, Flip-Flops mit kombinatorischer Logik zu entwerfen, aber außerhalb des Lernens ist dies im Allgemeinen keine gute Idee.

Danke für die Erklärungen, das meiste leuchtet mir ein. Ich verstehe jedoch nicht, warum Sie sagen, dass ich eher einen Latch als einen Flip-Flip implementiert habe - ich habe die Logik von hier aus modelliert , wo sie als flankengesteuert angezeigt wird. Außerdem sehe ich nicht, wie ich das Q/QN-Feedback vermisse. always_combSollte die Sensitivitätsliste nicht alle Variablen aus den enthaltenen Anweisungen ableiten? Vielleicht deuten Sie an, dass die Sperrzuweisungen das einzige Problem sind und Latch-/Feedback-Probleme davon abgeleitet sind?
Ich verstehe endlich, was Sie gesagt haben, dass mein JK nicht flankengesteuert ist (siehe meine Antwort). Ich weiß immer noch nicht, was Sie mit "Fehlendes Feedback zwischen Q und Qn" gemeint haben. Es scheint, als hätte ich dieses Feedback in meiner Logik - und es funktioniert so, wie es sollte.
Innerhalb einer Anfangs-Ende-Reihenfolge ist der Betrieb wichtig. Wenn Sie die Reihenfolge ändern, können Sie ein seltsames Verhalten feststellen. Weisen Sie beispielsweise im Always-Block 'Q' vor 'sn' zu.
Ich verstehe, worauf Sie hinauswollen, aber ich stimme Ihnen nicht zu. Meine Tests zeigen, dass es keine Reihenfolgeabhängigkeiten gibt (läuft unter Verilator). Dies ist ein interessantes Thema, und ich habe eine ausführliche Antwort als Antwort auf eine andere Frage gepostet: hier .
Ok, ich glaube, ich habe es jetzt verstanden – tut mir leid, ich komme gerade erst auf den neuesten Stand zu diesem Zeug. Ihre Kommentare zur Betriebsreihenfolge gehen von einer Simulation im Softwarestil oder vor der Synthese aus . Ich hatte diese Möglichkeit vorher nicht in Betracht gezogen, weil Verilator (oder echte Hardware) so nicht funktioniert. Diese Unterscheidung der Verilog-Semantik wird in Abschnitt 2.2 des Dokuments hier beschrieben . Ich bin verrückt geworden und habe hier nach dieser Unterscheidung gefragt .
Ah, Varilator läuft wie eine Postsynthese und hält sich daher nicht strikt an die Verilog/SystemVerilog-Standards. Das erklärt das Verhalten. Sie sollten auch Fehler beim Zuweisen von Typen in einem Always-Block erhalten haben wire. Cliff schreibt großartige Artikel; Ich beziehe mich auch auf sie, wenn ich mit Jenseits-der-LRM-Herausforderungen konfrontiert werde. Der IEEE Std 1800-2012 ist die neueste offizielle SystemVerilog-Spezifikation. Und zur Info: Auf EDAplayground können Sie auch andere Simulatoren ausprobieren .

Beschreibungen des JK-Flip-Flops neigen dazu, stark durcheinander zu sein. Insbesondere die Interaktion mit der Uhr scheint selten auf vollständig kohärente Weise beschrieben zu werden, aber dies kann größtenteils auf ein größeres Problem der lockeren und mehrdeutigen Verwendung von Terminologie zurückzuführen sein .

Das grundlegende Problem mit dem JK-Flip-Flop der Frage wird in dieser Antwort beschrieben . Kurz gesagt, das, was modelliert wird, ist trotz gegenteiliger Hinweise in dem referenzierten Wikipedia-Artikel nicht flankengetriggert .

Um ein flankengetriggertes JK-Flip-Flop zu bauen, können Sie eine zweistufige Konfiguration kaskadierter Latches (ein sogenannter "Master-Slave") verwenden - so dass sich die beiden Stufen während entgegengesetzter Taktphasen in einem transparenten vs. einem gehaltenen Zustand befinden . Bei dieser Anordnung hält die erste Stufe die Daten stabil, während sich die zweite Stufe in ihrem transparenten Zustand befindet. Diese Beziehung erzeugt den Flankentriggereffekt und wird unten implementiert ...

module dff( input clk, input D, output Q );
   wire Q1;
   jkff A(!clk,D,!D,Q1);
   jkff B(clk,Q1,!Q1,Q);
endmodule

... wo jkffist die gleiche Logik wie zuvor (würde aber besser als "JK-Gated-Latch" bezeichnet werden) ...

module jkff( input clk, input J, input K, output Q );

   wire sn, rn, qn;

always_comb
   begin
   sn = !(J&clk&qn);
   rn = !(K&clk&Q);
   Q  = !(sn&qn);
   qn = !(rn&Q);
   end

endmodule

Der berichtete Mangel an Konvergenz kann durch den nicht-konvergierenden Toggle-Modus des pegelgetriggerten Designs erklärt werden, wenn die Eingänge jemals den Zustand halten dürften (J = K = 1).

Von weiterem Interesse: Das Buch "Verilog HDL" von Samir Palnitkar enthält eine Implementierung eines D-Typ-Flip-Flops, die praktisch dem in der Frage gezeigten entspricht.

Um es explizit auszudrücken: Die Antwort auf die Eingangsfrage lautet: Ja, das ist vernünftig. Es gibt jedoch keine Garantie dafür, dass eine bestimmte Hardware in der Lage ist, solche Designs zu realisieren. Auch unterschiedliche Simulatoren können unterschiedliche Ergebnisse liefern – insbesondere im Hinblick auf die Unterscheidung zwischen Pre- und Post-Synthese-Simulation.