Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Verilog

Sequenzielle Logik mit immer

Ein früherer Artikel zeigte verschiedene Beispiele für die Verwendung eines always Block, um kombinatorische Logik zu implementieren. Eine always block wird auch hauptsächlich verwendet, um sequenziell zu implementieren Logik, die Speicherelemente wie Flip-Flops hat, die Werte halten können.

JK-Flip-Flop

Ein JK-Flip-Flop ist einer der vielen Typen von Flops, die zum Speichern von Werten verwendet werden, und hat zwei Dateneingänge j und k zusammen mit einem für das Zurücksetzen von rstn und einem anderen für den Takt clk. Die Wahrheitstabelle für ein JK-Flop ist unten dargestellt und wird typischerweise mit NAND-Gattern implementiert.

rstn j k q Kommentare
0 0 0 0 Wenn Reset aktiviert ist, ist die Ausgabe immer null
1 0 0 Wert halten Wenn sowohl j als auch k 0 sind, bleibt die Ausgabe die gleiche wie zuvor
1 0 1 1 Wenn k=1, wird die Ausgabe 1
1 1 0 0 Wenn k=0, wird die Ausgabe 0
1 1 1 Toggle-Wert Wenn j=1, k=1 Ausgang schaltet aktuellen Wert um

Der Verhaltens-Verilog-Code für ein JK-Flip-Flop kann wie unten gezeigt geschrieben werden

  
  
module jk_ff ( input 			j, 				// Input J
               input 			k, 				// Input K
               input 			rstn, 		// Active-low async reset
               input 			clk, 			// Input clk
               output reg q); 			// Output Q

	always @ (posedge clk or negedge rstn) begin
		if (!rstn) begin
			q <= 0;
		end else begin
	  	q <= (j & ~q) | (~k & q);
	  end
  end
endmodule

  

Testbench

Deklarieren Sie zunächst alle in der Testbench verwendeten Variablen und starten Sie eine Uhr mit einem einfachen always Block, der zum Design gefahren werden kann. Instanziieren Sie dann das Design und verbinden Sie seine Ports mit entsprechenden Testbench-Variablen. Beachten Sie, dass q vom Typ wire ist weil es mit einem Ausgang des Designs verbunden ist, das es aktiv antreibt. Alle anderen Eingaben für das Design sind vom Typ reg damit sie innerhalb eines prozeduralen Blocks wie initial gefahren werden können .

Der Stimulus initialisiert zuerst alle Eingaben in das Design auf null und deaktiviert dann nach einiger Zeit das Zurücksetzen. Ein for Schleife wird verwendet, um unterschiedliche Werte für j und k zu treiben, die zu zufälligen Zeiten getrieben werden. Wenn die Schleife fertig ist, warten Sie noch etwas und beenden Sie die Simulation.

  
  
module tb;
	// Declare testbench variables
	reg j, k, rstn, clk;
	wire q;
	integer i;
	reg [2:0] dly;
	
	// Start the clock 
	always #10 clk = ~clk;
	
	// Instantiate the design
	jk_ff 	u0 (	.j(j), .k(k), .clk(clk), .rstn(rstn), .q(q));
	
	// Write the stimulus
	initial begin
		{j, k, rstn, clk} <= 0;
		#10 rstn <= 1;
		
		for (i = 0; i < 10; i = i+1) begin
			dly = $random;
			#(dly) j <= $random;
			#(dly) k <= $random;
		end
		
		#20 $finish;
	end
endmodule

  

Beachten Sie aus der Simulationswelle, dass der Ausgang q im Takt der Uhr seinen Wert basierend auf dem Zustand der Eingänge j und k ändert, wie in der Wahrheitstabelle angegeben.

Modulo-10-Zähler

Modulus(MOD)-Zähler zählen einfach bis zu einer bestimmten Zahl, bevor sie auf Null zurückgesetzt werden. Ein MOD-N-Zähler zählt von 0 bis N-1 und rollt dann auf Null zurück und beginnt erneut zu zählen. Solche Zähler erfordern normalerweise log2 N Anzahl von Flops zum Halten des Zählwerts. Unten ist der Verilog-Code für einen MOD-10-Zähler gezeigt, der bei jedem Clock-Clk hochzählt, solange reset rstn deaktiviert ist.

Verilog-Parameter können verwendet werden, um einen skalierbareren MOD-N-Zähler zu erstellen.

  
  
module mod10_counter ( 	input		clk,
												input 	rstn,
												output	reg[3:0] out);
												
	always @ (posedge clk) begin
		if (!rstn) begin
			out <= 0;
		end else begin
			if (out == 10) 
				out <= 0;
			else
				out <= out + 1;
		end
	end
endmodule

  

Testbench

Die Testbench deklariert zuerst einige Variablen, denen einige Werte zugewiesen und zu den Designeingaben getrieben werden können. Das Zählermodul wird dann instanziiert und mit den Testbench-Signalen verbunden, die später mit einigen Werten im Stimulus angesteuert werden. Da der Zähler auch eine Uhr benötigt, wird die Testbench-Uhr mit einer always modelliert Block. Der Stimulus setzt einfach Standardwerte zum Zeitpunkt 0 ns, deaktiviert dann das Zurücksetzen nach 10 ns und lässt das Design für einige Zeit laufen.

  
  
module tb;
	reg clk, rstn;
	reg [3:0] out;
	
	mod10_counter u0 ( .clk(clk), .rstn(rstn), .out(out));
	
	always #10 clk = ~clk;
	
	initial begin
		{clk, rstn} <= 0;
		
		#10 rstn <= 1;
		#450 $finish;
	end
endmodule

  

Sehen Sie, dass das Zählermodul von Null bis 9 zählt, auf Null übergeht und erneut zu zählen beginnt.

Linkes 4-Bit-Schieberegister

Unten ist ein 4-Bit-Linksschieberegister gezeigt, das eine Eingabe d in LSB akzeptiert und alle anderen Bits um 1 nach links verschoben werden. Wenn beispielsweise d gleich Null ist und der Anfangswert des Registers 0011 ist, wird es 0110 bei die nächste Flanke der Uhr clk.

  
  
module lshift_4b_reg (  input d,                      
                        input clk,                    
                        input rstn,                   
                        output reg [3:0] out
                     );
 
   always @ (posedge clk) begin
      if (!rstn) begin
         out <= 0;
      end else begin
         out <= {out[2:0], d};
      end
   end
endmodule

  

Testbench

Die Testbench folgt einer ähnlichen Vorlage wie der zuvor gezeigten, in der einige Variablen deklariert, das Designmodul instanziiert und mit den Testbench-Signalen verbunden wird. Dann wird eine Uhr gestartet und der Stimulus wird mit einem initial zum Design getrieben Block. In diesem Testbench-Beispiel müssen verschiedene Werte von d ausgeübt werden und daher ein for Schleife wird verwendet, um 20 Mal zu iterieren und zufällige Werte auf das Design anzuwenden.

  
  
module tb;
	reg clk, rstn, d;
	wire [3:0] out;
  integer i;
	
  lshift_4b_reg u0 (  .d(d), .clk(clk), .rstn(rstn), .out(out));
	
	always #10 clk = ~clk;
	
	initial begin
    {clk, rstn, d} <= 0;
    
    #10 rstn <= 1;
	
    for (i = 0; i < 20; i=i+1) begin
      @(posedge clk) d <= $random; 
    end
    
    #10 $finish;
	end  
endmodule

  

Beachten Sie, dass jedes Bit um 1 nach links verschoben wird und der neue Wert von d auf LSB angewendet wird.


Verilog

  1. Tutorial - Schreiben von kombinatorischem und sequentiellem Code
  2. Schaltung mit Schalter
  3. Integrierte Schaltkreise
  4. Speicherprogrammierbare Steuerungen (SPS)
  5. Einführung in die Boolesche Algebra
  6. Logische Vereinfachung mit Karnaugh Maps
  7. Digitale Logik mit Feedback
  8. Verilog Mod-N-Zähler
  9. Verilog Grey Counter
  10. Immer ein glattes Finish mit Okamoto-Schleifmaschinen