Ansteuern einer 7-Segment-Anzeige mit einem Register vs. Draht

Als ich vor ein paar Tagen mein FPGA bekam, habe ich ein Modul erstellt, um meine 7-Segment-Anzeige anzusteuern. Ich habe nur kontinuierliche Zuweisungen verwendet, um die LEDs anzusteuern.

module set_number(input [3:0] x, output [6:0] seg);
    assign seg = x == 0 ? 7'b1000000 :
                 x == 1 ? 7'b1111001 :
                 x == 2 ? 7'b0100100 :
                 x == 3 ? 7'b0110000 :
                 x == 4 ? 7'b0011001 :
                 x == 5 ? 7'b0010010 :
                 x == 6 ? 7'b0000010 :
                 x == 7 ? 7'b1111000 :
                 x == 8 ? 7'b0000000 :
                 x == 9 ? 7'b0010000 : 
                          7'b1111111;
endmodule

Ich habe ein Buch gelesen und sie haben ein 7-Seg-Display, das so geschrieben ist und Register und einen kombinatorischen Always-Block verwendet.

module hex_to_sseg
(
 input  wire  [3:0]  hex,
 input  wire  dp,
 output  reg  [7:0]  sseg   // output active low
);

always @*
begin
   case(hex)
      4'h0:  sseg[6:0]  = 7'b0000001;
      4'h1:  sseg[6:0]  = 7'b1001111;
      4'h2:  sseg[6:0]  = 7'b0010010;
      4'h3:  sseg[6:0]  = 7'b0000110;
      4'h4:  sseg[6:0]  = 7'b1001100;
      4'h5:  sseg[6:0]  = 7'b0100100;
      4'h6:  sseg[6:0]  = 7'b0100000;
      4'h7:  sseg[6:0]  = 7'b0001111;
      4'h8:  sseg[6:0]  = 7'b0000000;
      4'h9:  sseg[6:0]  = 7'b0000100;
      4'ha:  sseg[6:0]  = 7'b0001000;
      4'hb:  sseg[6:0]  = 7'b1100000;
      4'hc:  sseg[6:0]  = 7'b0110001;
      4'hd:  sseg[6:0]  = 7'b1000010;
      4'he:  sseg[6:0]  = 7'b0110000;
      default:  sseg[6:0]  = 7'b0111000;   //4'hf
  endcase
  sseg[7] = dp;

Gibt es einen praktischen Unterschied zwischen meinem Ansatz mit dem Draht und dem Ansatz des Buches mit der Register- und Kombinationslogik?

Antworten (4)

Wie Transistor in seiner Antwort erwähnt, ist die Logik, die durch die beiden von Ihnen geposteten Codeteile dargestellt wird, nicht dieselbe. es hat Unterschiede in der Bitreihenfolge und das letztere Beispiel zeigt Hexadezimalzeichen AF an.

Aber Sie fragen nach dem Unterschied zwischen der Verwendung einer Wire-Variablen und einer Assign-Anweisung im Vergleich zu einer Reg-Variablen und einem Always-@*-Konstrukt.

Eine verwirrende Sache bei Verilog ist, dass die Verwendung eines Reg-Datentyps in Ihrem Code nicht immer bedeutet, dass ein Register in der synthetisierten Logik implementiert wird.

In den von Ihnen geposteten Fällen würden beide Lösungen mit kombinatorischer Logik ohne physische Register implementiert. Es ist sehr üblich, das Konstrukt always @* zu verwenden, um die kombinatorische Logik zu modellieren.

Sequentielle Schaltungen, die physische Register (Flip-Flops) enthalten, werden ebenfalls unter Verwendung des Always-Konstrukts modelliert, aber diese Schaltungen haben ein Posedge- und/oder Negedge-Signal, das in der Empfindlichkeitsliste angegeben ist.

Von den Fällen, die Sie gepostet haben, würde ich persönlich es vorziehen, die immer @*-Version des Codes zu verwenden, da ich denke, dass sie die Absicht des Codes klarer zeigt; Es ist leicht zu erkennen, dass es sich um eine Decodiertabelle handelt.

Genau aus diesem Grund hat SystemVerilog das regSchlüsselwort durch logic go.mentor.com/wire-vs-reg ersetzt

Viele Synthesizer verwenden den Bedingungsoperator Treat ( ?:) als expliziten 2:1-Mux. Verschachtelte bedingte Operatoren mit Synthetisieren während des Schreibens des Designs. In Ihrem Fall wird es eine Kette von zehn 2:1-Musen sein. Hier ist ein Diagramm Ihres Codes, der mit Yosys 0.3.0 auf edaplayground synthetisiert wurde

mit Assign-Anweisung

Indem Sie Ihren Code in eine Case-Anweisung konvertieren, wird er wie folgt synthetisiert (auch synthetisiert mit Yosys 0.3.0 auf edaplayground ). In diesem Fall verwendete Yosys einen Prioritäts-Mux, aber es hätte genauso einfach einen auswählen können

mit Case-Anweisung in einem Always-Block

Funktional sind beide identisch. Die Case-Statement-Version hat normalerweise ein besseres und gleichmäßigeres Timing. Bei den verschachtelten bedingten Operatoren, wenn x==0die Prorogationsverzögerung 2 Logikgatter beträgt, wenn x>=9sie 11 Logikgatter beträgt. Die Case-Statement-Version verleiht dem Synthesizer auch mehr Flexibilität, was dem Synthesizer ermöglicht, die besten Optionen für die Situation auszuwählen, wobei verfügbare Ressourcen, Ressourcen, die für andere Logik benötigt werden, und Zeitsteuerungsanforderungen berücksichtigt werden.

Im Allgemeinen ist es besser, eine Case-Anweisung zu verwenden und den Synthesizer die geeigneten Muxes auswählen zu lassen.

Es gibt verschiedene Möglichkeiten, dieselbe Beschreibung in Verilog auszudrücken. Die kontinuierliche assignAnweisung ist gut, um eine Gleichung für ein einzelnes Signal zu schreiben, aber es ist nicht wirklich RTL. Wenn Sie mehrere Signale basierend auf demselben Satz von Eingaben zuweisen möchten, können alwaysSie mit dem Block den Fluss der Entscheidungen anzeigen, die in einem prozeduralen Codeblock getroffen werden. Dies ist eine viel bessere Möglichkeit, Ihre Absicht zu zeigen, indem Sie eine Reihe von besser lesbaren RTL-Anweisungen verwenden.

Wenn Ihre Bedenken die Binärwerte betreffen, sieht es in Ordnung aus. Der Beispielcode weist zwei Unterschiede auf.

  • Die Bitreihenfolge ist umgekehrt. Dies kann neu angeordnet werden, um dem PCB-Layout zu entsprechen.
  • Die Buchversion zeigt den vollständigen Hex-Zeichensatz an, während Ihre nur Dezimalziffern verarbeitet.
  • Das Buch scheint ein anderes Ausgaberegister zu verwenden.
Ich verstehe diese Unterschiede. Ich verstehe einfach nicht, warum das Buch einen Always-Block mit einem Register verwendet, wenn Sie es mit Assign einfach viel einfacher machen können.
Tut mir leid, das weiß ich nicht. Mal sehen, wer sich noch einmischt.