Probleme bei der Implementierung eines 1-Hz-Blinklichts auf einem Spartan 6-FPGA

Ich habe derzeit ein Spartan-6-FPGA in einem Digilent Nexus 3-Board. Ich verwende Xilinx 14.6 Project Navigator, um den Code zu schreiben und das FPGA zu programmieren.

Mein Code für das oberste (und einzige) Modul lautet wie folgt:

21 module blinker(
22 input clk,
23 output reg led_state
24 );
25   
26 reg [31:0] count;
27 wire count_max = 32'd50000000;
28
29 assign count_next = (count_next > count_max) ? 32'd00000000 : count + 32'd00000001;
30 assign led_next = (count == count_max) ? ~led_state : led_state;
31
32 always @(posedge clk)
33 begin
34    count <= count_next;
35    led_state <= led_next;
36 end
37
38 endmodule

Laut Nexus 3-Referenzhandbuch hat das Board einen 100-MHz-Oszillator an Pin V10, und so habe ich in meiner Benutzerbeschränkungsdatei den V10-Pin dem clk-Eingangssignal meines Moduls zugeordnet.

Da der Oszillator bei 100 MHz liegt, setze ich count_max auf 50.000.000, sodass der led_state alle 50 x 10 ^ 6 clk-Flanken oder jede halbe Sekunde bei 100 MHz invertieren sollte.

Als ich versuchte, eine Synthese mit XST im Projektnavigator durchzuführen, erhalte ich diese Warnmeldungen:

WARNING:HDLCompiler:413 - "C:\Users\Public\Documents\Xilinx Projects\blinker\blinker.v" Line 29: Result of 32-bit expression is truncated to fit in 1-bit target.
WARNING:Xst:2404 -  FFs/Latches <count<31:1>> (without init value) have a constant value of 0 in block <blinker>.
WARNING:Xst:2170 - Unit blinker : the following signal(s) form a combinatorial loop: n0011<0>.

Ich kann jedoch immer noch die .bit-Datei erstellen und das Nexus 3 programmieren. Das Ergebnis ist jedoch, dass die LED, die ich durch den Ausgang bezeichnet habe, einfach die ganze Zeit an blieb (es sei denn, sie blinkt). so schnell, dass ich nicht bemerke, dass es blinkt).

Ich dachte, dass es vielleicht mit der Warnung zu tun hat, wo der Synthesizer den Ausdruck in Zeile 29 abgeschnitten hat, also habe ich versucht, count_next als 32-Bit-Vektor [31:0] zu deklarieren, sowohl als Reg als auch als Wire, und ihn auch zu initialisieren Wert. Versuchte den Synthesizer und ich bekomme stattdessen Fehler.

Das Deklarieren und Initialisieren von count, led_state, count_next, led_next hat auch nicht funktioniert.

Ich habe mich gefragt, ob sich jemand das ansehen und mir sagen kann, was mit dem Code nicht stimmt. Es gibt auch eine kombinatorische Schleife für das Signal "n0011<0>", die ich nicht kenne.

Ich kenne Verilog nicht, aber Sie sollten count_nextden Ausdruck nicht verwenden, um count_next. Das ist, genau wie die Fehlermeldung sagt, eine kombinatorische Schleife. Ich bin mir ziemlich sicher, dass Sie hier verwenden wollten count.

Antworten (3)

Das Problem, das ich sehe, ist, count_maxdass Sie einen 1 Bit breiten Draht deklariert haben und ihm dann eine 32-Bit-Konstante zuweisen - dies wird im Wesentlichen auf 1 Bit gekürzt.

Dies bedeutet dann, dass Sie in Zeile 29 Additionen und Vergleiche zwischen 32-Bit- und 1-Bit-Werten durchführen, sodass Sie das Problem erhalten, dass 32-Bit auf 1-Bit verkürzt werden.

Dann werden Ihre Berechnungen durch Erweiterung auf einen einzigen 1-Bit-Wert optimiert (im Wesentlichen läuft es auf ab if >0, set to 0, else add 1), der immer nur 0 oder 1 sein wird und daher Ihre count[31:1](beachten Sie nicht das LSB, Bit 0) im Always-Konstrukt unverändert bleiben - weil Sie zuweisen sie auf immer 0.

Auch eine count_nextspezifische Deklaration würde helfen - Sie weisen einem nicht vorhandenen Draht zu, sodass ein Draht für Sie erstellt wird. Bei manchen Tools zB Modelsim wäre das ein Fehler, bei anderen zumindest eine Warnung. Der einfachste Weg, dies zu tun, wäre das Ersetzen assign count_nextdurch wire [31:0] count_next.

Wie Brian in den Kommentaren zu Recht betont, ist Ihre Bedingung schließlich falsch. Sie verwenden es count_nextals Teil seiner eigenen Assign-Anweisung, was einfach schlecht ist. Dies ist mit getakteten Registern problemlos möglich , da kein Risiko besteht, ein Design zu erstellen, das mit sehr hohen Frequenzen schwingt und möglicherweise das FPGA beschädigt. Ich glaube was du meinst ist (count >= count_max). Beachten Sie, dass ich auch zu >= geändert habe, das liegt daran, dass Ihre Zählung Null enthält - sagen Sie count_max = 5, Sie möchten, dass Ihr Zähler 0,1,2,3,4,0 geht - beachten Sie, wie 5 Taktzyklen benötigt werden von 0 bis 4 zählen und dann wieder auf 0 zurückgehen?

Danke. Ich bin sehr neu bei Verilog und Sie haben klargestellt, warum mein Code nicht funktioniert. Ich habe einfach alles verhaltensmäßig im Block always @(posedge clk) mit bedingten Anweisungen und Zählern implementiert, während ich Datenflusszuweisungen verwendet habe, um letztendlich ein Register einem Ausgang zuzuweisen. Ich bin besser mit C++ vertraut, daher ist dies für mich einfacher.

Ihre count_next-Leitung wird implizit deklariert. Das bedeutet, dass es ein Bit breit ist, daher wird count [31: 1] nie zugewiesen und Sie erreichen nie Ihre maximale Anzahl, die auch als 32 Bit und nicht als 1 Bit deklariert werden muss, wie Tom betonte.

wire [31:0] count_next;
localparam count_max = 32'd50000000;  //you can use a wire but a parameter is a better description for a run time constant.

Es gibt mehrere andere Probleme, wie von anderen erwähnt.

  • count_max sollte ein Parameter sein (oder besser in diesem Fall ein localparam).
  • Verwenden Sie count not count_next in Ihrer Aufgabe.
  • Fügen Sie einen Reset hinzu oder initialisieren Sie für die FPGA-Synthese nur Ihre Register.
  • Simulieren Simulieren Simulieren. Diese Probleme sind viel einfacher zu debuggen und in der Simulation viel offensichtlicher. Siehe http://www.edaplayground.com/, wenn Sie einen brauchen, aber Xilinx enthält glaube ich auch isim kostenlos im Webpack.
Einem Draht eine Konstante zuzuweisen ist in Ordnung. Es gibt keinen Grund, es durch einen Parameter außer der Konvention zu ersetzen. Eigentlich ist das Argument dafür, es als Draht zu belassen, dass Sie es mit einem anderen Stück Logik verbinden könnten, um die Frequenz dynamisch zu ändern. Wenn Sie nur einen konstanten Wert zuweisen, drückt der Synthesizer die Konstanten und entfernt die Verbindung.
@alex.forencich Als ich meine Antwort entfernt habe, bin ich auf diesen Thread gestoßen , in dem es um die Initialisierung geht. Unter anderem wird darauf hingewiesen, dass diese Art der Initialisierung auf FPGAs funktioniert, aber nicht auf ASICs oder CPLDs.
Die konstante Zuordnung zu einem Draht sollte überall funktionieren, da der Synthesizer dies durch ständiges Drücken optimiert.
Ich stimme zu, Sie können einem Draht eine Konstante zuweisen. Je größer Ihre Codebasis wird, desto schwieriger wird es, sie zu lesen, je mehrdeutiger die Absicht Ihres Codes ist. Ein Parameter ist eine direkte und eindeutige Beschreibung einer Laufzeitkonstante. Allerdings liegt es an den Benutzern zu entscheiden, wie viel Aufwand in die Wartbarkeit gesteckt wird oder ob dies ein Platzhalter für zukünftige dynamische Zuweisungen ist.

Initialisieren Sie Ihre Zählregistrierung auf Null und geben Sie die richtige Breite für den count_next-Draht an. Sollte gut funktionieren, sobald Sie diese Änderungen vorgenommen haben.