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?
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.
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
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
Funktional sind beide identisch. Die Case-Statement-Version hat normalerweise ein besseres und gleichmäßigeres Timing. Bei den verschachtelten bedingten Operatoren, wenn x==0
die Prorogationsverzögerung 2 Logikgatter beträgt, wenn x>=9
sie 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 assign
Anweisung 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 always
Sie 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.
dave_59
reg
Schlüsselwort durchlogic
go.mentor.com/wire-vs-reg ersetzt