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

Verilog N-Bit Bidirektionales Schieberegister – Design und Implementierung

In der Digitaltechnik ist ein Schieberegister eine Kaskade von Flipflops, bei der der Ausgangspin q eines Flops mit dem Dateneingangspin (d) des nächsten verbunden ist. Da alle Flops am gleichen Takt arbeiten, verschiebt sich das im Schieberegister gespeicherte Bit-Array um eine Position. Beispiel: Ein 5-Bit-Rechtsschieberegister mit dem Anfangswert 10110 und Eingang 0 erzeugt im nächsten Takt 01011 und dann 00101.

Design

Dieses Schieberegister-Design hat fünf Eingänge und einen n-Bit-Ausgang und ist über parameter MSB parametriert, um die Breite des Schieberegisters festzulegen. Wenn n=4, wird es ein 4-Bit-Schieberegister; bei n=8 ein 8-Bit-Schieberegister.

Dieses Schieberegister hat folgende Hauptmerkmale:

module shift_reg #(parameter MSB=8) (
  input d,      // Dateneingang für erstes Flop
  input clk,    // Takt für alle Flops
  input en,     // Enable zum Ein-/Ausschalten
  input dir,    // Schieferichtung: 0=rechts, 1=links
  input rstn,   // Active-Low-Reset
  output reg [MSB-1:0] out  // Aktueller Wert aller Flops
);
  // Always-Block wird an steigender Taktflanke getriggert
  always @ (posedge clk)
    if (!rstn) out <= 0;
    else begin
      if (en) case (dir)
        0 : out <= {out[MSB-2:0], d};  // Rechtsschieben
        1 : out <= {d, out[MSB-1:1]};  // Linksschieben
      endcase
      else out <= out;  // Bei deaktiviertem Enable: Wert halten
    end
endmodule

Hardware-Schaltplan

Testbench

Der Testbench verifiziert die Funktionalität dieses Schieberegisters. Das Design wird in das Top-module instanziiert und die Eingänge werden mit verschiedenen Werten getrieben. Das Design-Verhalten für jede Eingabe kann am Ausgangspin out beobachtet werden.

module tb_sr;
  parameter MSB = 16;  // Optionaler Parameter für Bitbreite
  reg data;            // Variable für d-Eingang
  reg clk;             // Variable für Takt
  reg en;              // Variable für Enable
  reg dir;             // Variable für Schieferichtung
  reg rstn;            // Variable für Reset
  wire [MSB-1:0] out;  // Wire für Design-Ausgang
  
  // Design instanziieren (16-Bit Schieberegister) mit MSB-Parameter
  shift_reg #(MSB) sr0 (
    .d(data), .clk(clk), .en(en), .dir(dir), .rstn(rstn), .out(out)
  );
  
  // Takt erzeugen: Periode 20ns -> Frequenz 50MHz
  always #10 clk = ~clk;
  
  // Variablen zum Zeitpunkt 0 initialisieren
  initial begin
    clk <= 0; en <= 0; dir <= 0; rstn <= 0; data <= 'h1;
  end
  
  // Hauptstimulus für Design-Verifikation
  initial begin
    // 1. Reset anwenden und nach einiger Zeit deaktivieren
    rstn <= 0; #20 rstn <= 1; en <= 1;
    
    // 2. Für 7 Takte abwechselnde Werte an data-Pin
    repeat (7) @ (posedge clk) data <= ~data;
    
    // 3. Schieferichtung ändern und für weitere 7 Takte abwechselnde Werte
    #10 dir <= 1;
    repeat (7) @ (posedge clk) data <= ~data;
    
    // 4. Nichts für nächste 7 Takte treiben, Register schiebt basierend auf dir
    repeat (7) @ (posedge clk);
    
    // 5. Simulation beenden
    $finish;
  end
  
  // Variablen überwachen und in Logfile ausgeben
  initial $monitor("rstn=%0b data=%b, en=%0b, dir=%0b, out=%b", rstn, data, en, dir, out);
endmodule

Die Zeit, in der das Schieberegister aktiviert ist, ist im untenstehenden Log grün markiert. Die Zeit des Richtungswechsels ist gelb markiert. Die Zeit, in der der Dateneingang konstant bleibt, ist blau markiert.

Simulations-Log:

ncsim> run
rstn=0 data=1, en=0, dir=0, out=xxxxxxxxxxxxxxxx
rstn=0 data=1, en=0, dir=0, out=0000000000000000
rstn=1 data=1, en=1, dir=0, out=0000000000000000
rstn=1 data=0, en=1, dir=0, out=0000000000000001
rstn=1 data=1, en=1, dir=0, out=0000000000000010
rstn=1 data=0, en=1, dir=0, out=0000000000000101
rstn=1 data=1, en=1, dir=0, out=0000000000001010
rstn=1 data=0, en=1, dir=0, out=0000000000010101
rstn=1 data=1, en=1, dir=0, out=0000000000101010
rstn=1 data=0, en=1, dir=0, out=0000000001010101
rstn=1 data=0, en=1, dir=1, out=0000000001010101
rstn=1 data=1, en=1, dir=1, out=0000000000101010
rstn=1 data=0, en=1, dir=1, out=1000000000010101
rstn=1 data=1, en=1, dir=1, out=0100000000001010
rstn=1 data=0, en=1, dir=1, out=1010000000000101
rstn=1 data=1, en=1, dir=1, out=0101000000000010
rstn=1 data=0, en=1, dir=1, out=1010100000000001
rstn=1 data=1, en=1, dir=1, out=0101010000000000
rstn=1 data=1, en=1, dir=1, out=1010101000000000
rstn=1 data=1, en=1, dir=1, out=1101010100000000
rstn=1 data=1, en=1, dir=1, out=1110101010000000
rstn=1 data=1, en=1, dir=1, out=1111010101000000
rstn=1 data=1, en=1, dir=1, out=1111101010100000
rstn=1 data=1, en=1, dir=1, out=1111110101010000
Simulation complete via $finish(1) at time 430 NS + 0

Verilog

  1. Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
  2. Verilog Concatenation meistern: Praktischer Leitfaden
  3. Verilog Assignments verstehen: Typen, Syntax und Best Practices
  4. Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
  5. Verilog Functions meistern für effizientes RTL-Design
  6. Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
  7. Verilog Clock Generator: Design & Implementierungsleitfaden
  8. Verilog Math Functions meistern für effizientes Hardware-Design
  9. Verilog $timeformat meistern: Präzision und Anzeigesteuerung
  10. Verilog Timescales an jedem Scope verstehen und ausgeben