Schieberegister korrekt initialisieren (Verilog)

Ich habe mit einem sehr einfachen Verilog-Programm zu kämpfen. Es ist ein 4-Bit-Schieberegister, das bei jedem Taktzyklus gedreht wird und vier LEDs ansteuert. (Wie Sie sehen, bin ich neu bei FPAGs und HDLs.)

Das Problem : Untenstehender Code wird ohne Warnungen synthetisiert und erfolgreich in das FPGA programmiert. Beim Start passiert dann nichts, die LEDs bleiben dunkel. Der i_Switch_1Eingang wurde hinzugefügt, um überhaupt etwas zu bewirken, und tatsächlich, wenn ich den Schalter drücke, beginnen die LEDs zu rotieren.

Hier ist der Verilog-Code:

Version 1 (fehlgeschlagen)

module top
   (input i_Clk, 
    input i_Switch_1,
    output o_LED_1,
    output o_LED_2,
    output o_LED_3,
    output o_LED_4
   );

     reg [3:0]shift_reg;

     initial
         shift_reg = 4'b0001;   // has no effect

     always @(posedge i_Clk)
     begin
         shift_reg <= i_Switch_1 ? 4'b0001 : {shift_reg[2:0], shift_reg[3]};
     end

     assign o_LED_1 = shift_reg[0];
     assign o_LED_2 = shift_reg[1];
     assign o_LED_3 = shift_reg[2];
     assign o_LED_4 = shift_reg[3];

 endmodule

Bewertung : Meine bisherige Schlussfolgerung ist, dass shift_regnicht auf 1 initialisiert wird. Die RTL-Ansicht unten zeigt, dass keine Initialisierung synthetisiert wird.Schieberegister

Ich habe an vielen Stellen gelesen, dass der Anfangsblock synthetisierbar ist, also bin ich jetzt wirklich verwirrt.

Frage 1 : Ist meine Einschätzung richtig?

Frage 2 : Angenommen, meine Einschätzung ist richtig, was ist die Abhilfe? Ich habe verschiedene Dinge ausprobiert und nichts davon funktioniert:

  • Route in den Reset-Pin, aber das scheint nicht erlaubt zu sein.
  • Verwenden Sie einen shift_reg==0Vergleich (Version 2 unten)
  • Verwenden Sie eine is_initFlagge (Version 3 unten)

Ich fange an zu glauben, dass ich etwas grundlegend falsch mache. Was ist los??

Version 2 (fehlgeschlagen)

shift_reg <= (shift_reg==0 || i_Switch_1) ? 1 : {shift_reg[2:0], shift_reg[3]}

Version 3 (fehlgeschlagen)

reg is_init; 
initial
    is_init = 0;   // Must have this or else the is_init gets optimized out!

always @(posedge i_Clk)
begin
    if(~is_init || i_Switch_1) begin
        is_init <= 1;
        shift_reg <= 4'b0001;
    end
    else begin
        is_init <= 1;
        shift_reg <= {shift_reg[2:0], shift_reg[3]};
    end
end

Setup : LatticeSemi iCE40HX1K (Nandland Go Board) mit iCEcube2, Synthesetool ist Synplify Pro.

--

Aktualisieren

Das hier funktioniert:

Version 4 (Erfolg)

reg [3:0]shift_reg = 0;

always @(posedge i_Clk)
begin
    case(shift_reg)
    1: shift_reg <= 2;
    2: shift_reg <= 4;
    4: shift_reg <= 8;
    8: shift_reg <= 1;
    default: 
        shift_reg <= 1;
    endcase
end

Aber das Syntheseergebnis ist etwas aufgebläht:richtig initialisiertes Schieberegister über case-Anweisung

Warum kannst du Reset nicht verwenden?

Antworten (2)

In vielen Fällen unterstützen FPGAs keine Einschalt-Anfangswerte von etwas anderem als 0. Ich weiß, dass alle Altera-FPGAs, mit denen ich gearbeitet habe, dies nicht tun. Tatsächlich ist dies laut Datenblatt für Ihr FPGA tatsächlich der Fall:

Jedes DFF ist auch mit einem globalen Rücksetzsignal verbunden, das automatisch unmittelbar nach der Gerätekonfiguration geltend gemacht wird.

Globales Zurücksetzen schlägt 0 vor, es würde gesetzt werden, wenn es zu einer 1 führen würde.

Um dies zu umgehen, tun einige Synthesewerkzeuge etwas, das Bubble Pushing genannt wird - alles, was auf 1 initialisiert werden sollte, wird stattdessen auf 0 initialisiert und dem Ausgang wird ein Not-Gate hinzugefügt. Es scheint jedoch in Ihrem Fall, dass das Synthesetool dies nicht richtig macht. Sie können es tatsächlich manuell versuchen, wenn Sie möchten:

...
shift_reg <= {shift_reg[2:1], !shift_reg[0], shift_reg[3]};
...
assign o_LED_1 = !shift_reg[0];

Wobei das auf Dauer nicht besonders sinnvoll ist.

Sie können auch die alternative Methode zur Angabe des Anfangswerts ausprobieren und sehen, ob das Synthese-Tool einen besseren Job macht:

reg [3:0] shift_reg = 4'b0001;

--

Jedenfalls verlassen wir uns im Allgemeinen nicht auf einen Anfangswert für Register und Logik. Stattdessen haben wir ein globales Reset-Signal und Reset-Klauseln in der Logik. Dadurch können wir alle Register jederzeit auf einen bekannten Zustand setzen, ohne einen Power Cycle durchführen zu müssen.

In Ihrem Beispiel mit dem Schalter scheint Ihr Code mit dem darin enthaltenen Schalter ein Reset-Signal korrekt abgeleitet zu haben ( R_PATnehme ich an), das wie erwartet von angesteuert wird i_Switch_1. Typischerweise verwenden wir jedoch ein etwas anderes Format für Reset-Signale:

always @ (posedge clock) begin
    if (reset) begin
        // Do stuff here when in reset
    end else begin
        // Do stuff here when not in reset
    end
end
Ich habe endlos damit herumgespielt und meine Schlussfolgerung ist immer noch, dass die Lattice-Synthese-Tools (Lattices eigenes und 'Synplify') davon ausgehen, dass alle DFFs beim Start als 'b0' initialisiert werden. Das stimmt mit dem überein, was das Datenblatt sagt - wie Sie betonen. Was mich irritiert, ist, dass ein reg [3:0] r = 1'b1 stillschweigend durch reg r = 1'b0 ersetzt wird. Keine Meldung irgendeiner Art warnt mich davor.

Die strukturierte prozedurale Anweisung „initial“ ist nicht synthetisierbar. Um den Wert zu initialisieren, wenn Ihr FPGA eingeschaltet wird, können Sie den Wert des Registers initialisieren, indem Sie den Wert zum Zeitpunkt der Deklaration angeben. z.B.

reg [3:0]shift_reg= 4'b0000;

Ich habe das versucht, aber die mir zur Verfügung stehenden Synthesewerkzeuge (Lattice und "Synplify") ignorieren effektiv jede explizite oder implizite anfängliche Aussage. Es scheint mir, dass die Initialisierung von Registern (DFFs) nicht so synthetisiert werden kann. Stattdessen muss ich einen FSM bauen, der korrekt mit DFFs funktioniert, die beim Einschalten als 1'b0 initialisiert werden.
Ich stimme Hescham zu. Das ist der Grund, warum Ihre Fallaussage funktioniert. Die Abtretung zum Zeitpunkt der Deklaration ist Bestandteil von systemverilog. Überprüfen Sie möglicherweise die Kompiliermeldungen, um festzustellen, ob sie vom Compiler ignoriert werden. Sie könnten die Platz- und Routenbeschränkungen ausprobieren, mit denen Sie den Einschaltzustand des Registers festlegen können.