Warum wird dieses Verilog-Modul des Power-On-Reset-Generators optimiert?

Ich versuche, ein Verilog-Modul zu schreiben, das für einige Taktzyklen ein Einschalt-Rücksetzsignal erzeugt. Ich synthetisiere mit Lattice iCEcube2 + Synplify Pro, das auf einen iCE40 HX1K auf dem Nandland Go Board abzielt .

Wenn ich das Modul so schreibe, wird es optimiert:

`default_nettype none

module reset_generator #(
  parameter COUNT_WIDTH = 2
) (
  input wire    i_clk,
  output wire   o_rst
);

  reg [COUNT_WIDTH:0]   rst_count;
  assign o_rst = !rst_count[COUNT_WIDTH];

  always @(posedge i_clk) begin
    if (o_rst == 1) begin
      rst_count <= rst_count + 1;
    end
  end
endmodule

iCEcube2 gibt diese Warnung aus:

...
@N:CL189 : reset_generator.v(13) | Register bit rst_count[4] is always 1.
@N:CL159 : reset_generator.v(6) | Input i_clk is unused.
...
@N:BN115 : ball_absolute_mv_vga_top.v(19) | Removing instance reset_gen (in view: work.ball_absolute_mv_vga_top(verilog)) of type view:work.reset_generator_4s(verilog) because it does not drive other instances.
...

Und ich kann überprüfen, dass das o_rstSignal tatsächlich nie auf gesetzt ist 1. Ich dachte, alle Register wurden initialisiert 0, also bin ich mir nicht sicher, warum es denkt rst_count[4] is always 1.

Wenn ich jedoch explizit rst_countauf setze 0, so:

  reg [COUNT_WIDTH:0]   rst_count = 0;

Jetzt wird es nicht mehr optimiert und funktioniert wie erwartet, aber iCEcube2 zeigt diese Warnung:

@W:FX1039 : reset_generator.v(13) | User-specified initial value defined for instance reset_gen.rst_count[4:0] is being ignored. 

Diese Warnung impliziert auch, dass die Anfangswerte 0 sind. Warum wird also die erste Version optimiert? Und warum ändert das Hinzufügen eines anfänglichen Werts, der ignoriert wird, das Verhalten? Ist das nur eine Eigenart von iCEcube2 und/oder Synplify Pro?

BEARBEITEN 1 : Ich verwende einen Einschalt-Reset, da Lattice Register nur auf Null initialisieren kann und ich möchte, dass einige mit Werten ungleich Null beginnen.

Die o_rstdieser reset_generatorKomponente ist wie folgt mit einer anderen Komponente auf einer höheren Ebene verbunden:

  wire w_reset;
  reset_generator #(
    .COUNT_WIDTH(4)
  ) reset_gen (
    .i_clk(i_clk),
    .o_rst(w_reset)
  );

  ball_absolute ball_absolute (
    .clk(i_clk),
    .reset(w_reset),
    .vsync(o_vga_vsync),
    // ...
  );

Der Grund dafür ist, dass es ball_absoluteein Paar X/Y-Register für die Position des Balls auf dem Bildschirm hat. Ich möchte, dass der Ball in der Mitte des Bildschirms beginnt, nicht bei (0, 0). Und da Lattice Register nur auf initialisieren kann 0, möchte ich ein Power-On-Reset-Signal verwenden, um X/Y auf Werte ungleich Null zu setzen.

Das vollständige Projekt ist tatsächlich auf GitHub verfügbar .

EDIT 2 : Ich verstehe auch, dass ein PLL-Lock-Signal als Power-On-Reset verwendet werden könnte, aber leider hat der HX1K keine PLLs. Das Go Board verwendet einen externen Kristall für die Uhr.

Ihr Designansatz ist nicht gut. Normalerweise haben Sie einen externen Reset-Eingang, um interne Register Ihrer Reser-Generator-Logik zurückzusetzen/zu initialisieren. Die Logik kann daraus einen mehrzyklischen synchronen Reset erzeugen, um verschiedene Module im System zurückzusetzen.
Wie wird rst_count zurückgesetzt?
Sie können unter stackoverflow.com/a/38032139/9609830 nachsehen – es gibt viele Informationen, die Ihr Problem lösen könnten.
@ user253751: Tut es nicht. Es beginnt beim 0Einschalten und zählt aufwärts. Sobald o_rster niedrig ist, rst_countbleibt er für immer auf dem gleichen Wert ungleich Null.
@ChristianB.: Dieser Link bestätigt, was ich sehe. Es besagt, dass Lattice den Initialisierungswert ignoriert und alle FFs auf Null initialisiert. Es erklärt jedoch nicht, warum Lattice das Modul optimiert, wenn der Initialisierungswert fehlt. Außerdem hat der HX1K keine PLL, daher ist es nicht möglich, diese zum Zurücksetzen des Treibers zu verwenden.
@DaveDribin, warum startet es beim Einschalten bei Null? Sie benötigen eine Reset-Schaltung, um zu wissen, wo sie startet.
@ThePhoton: Alle Flip-Flops werden beim Einschalten auf Null initialisiert. Vielleicht ist das eine Eigenart von Lattice FPGAs und Tools? Ich weiß nicht, wie andere FPGAs und Tools funktionieren.
Warum müssen Sie in diesem Fall einen Power-On-Reset im FPGA-Fabric implementieren?
Können Sie auch Ihren Top-Level-Code teilen? rst_count[4]Ohne dies können wir nicht beantworten, warum Sie die Meldung "...treibt keine anderen Instanzen" erhalten haben, und wir können auch nicht erkennen, warum ein standardmäßig mit 3 Bits deklarierter Zähler ein 5. Bit ( ) haben würde.
@ThePhoton: Die Frage wurde mit dem "Warum" und einem Ausschnitt aus der obersten Ebene aktualisiert.

Antworten (1)

Dies ist wahrscheinlich eine Eigenart in synplify. Synplify ist für die Synthese von Designs für ASICs, nicht für FPGAs gedacht, und ist daher ziemlich eigensinnig. Bei ASICs ist es üblich, überhaupt nichts zu initialisieren und stattdessen explizite Resets zu verwenden. Infolgedessen behandelt synplify Initialblöcke und Inline-Initialisierer anders als FPGA-Tools – insbesondere ignoriert es sie meistens, selbst wenn es zu seltsamem, unerwartetem Verhalten kommt. Alle nicht explizit initialisierten Signale beginnen jedenfalls nicht bei 0, sondern bei X (unbestimmter Logikpegel). Und dann können die Tools während der Synthese einen beliebigen Wert auswählen, wenn dies die Logik vereinfachen kann. Es scheint also, was synplify hier tut ... Es bemerkt, dass es dieses bestimmte X in eine 1 auflösen kann und als Ergebnis eine Menge Logik löscht. Wenn Sie diese Registrierung auf 0 initialisieren, dann kann synplify diese Optimierung nicht vornehmen, aber es warnt Sie, dass der Initialisierer ignoriert wird, da synplify nicht versteht, wie die Register tatsächlich initialisiert werden, da Sie dies auf einem ASIC nicht tun können. Was Sie tun sollten, ist, den Inline-Init auf Null zu halten, aber auch einen externen Reset-Eingang hinzuzufügen, der dieses Register ebenfalls zurücksetzen kann.

Danke sehr hilfreich! Ich denke, das erklärt, was los ist. Aber warum empfehlen Sie einen externen Reset-Eingang? Ich verwende den Einschalt-Reset, um einige Register auf Werte ungleich Null zu initialisieren, da Lattice dazu nicht in der Lage ist. Ich glaube nicht, dass ich nach dem Einschalten zurücksetzen muss?
Und was meinst du mit externem Reset? Wie ein physischer Knopf oder so? Das Go Board hat 4 Druckknöpfe, aber ich möchte keinen als "Reset" -Knopf verwenden, wenn ich nicht muss. Ich könnte eine Tastenkombination machen, aber das scheint eine unnötige Komplikation zu sein?
Nun, ich denke, es kommt darauf an, was die Absicht ist. Normalerweise widme ich dem Zurücksetzen einen Button, aber auf vielen Boards gibt es für diesen Zweck einen dedizierten "cpu_rst"-Button. Aber es ist auch fast immer eine PLL beteiligt, so dass der interne Reset von dem PLL-verriegelten Ausgang abgeleitet wird und der PLL-Reset von dem externen Eingang kommen würde. Wenn Sie jedoch keine PLL haben und keinen externen Reset-Eingang benötigen, ist dies meiner Meinung nach nicht unbedingt erforderlich.
Leider hat die HX1K keine PLLs. Es verwendet eine externe Uhr als Quarz. Die Absicht besteht darin, einige Register auf Werte ungleich Null zu initialisieren, da iCEcube dies nicht zulässt. Ich denke, hier ist das Richtige, rst_count = 0die Warnung zu setzen und zu ignorieren.
Ja, klingt für mich vernünftig, wenn Sie keinen Druckknopf zum Zurücksetzen zuweisen möchten.