Uhrproblem mit Spartan 6

Ich habe einen Taktteiler wie folgt implementiert:

module sync_out(
  input clk,            // This is the FPGA system clock
  output reg sync       // This is the generated sync signal to be tested
);
  localparam
    SYNC_OUT_CLOCK_RATIO = 20;

  reg [10:0] counter;   // Clock counter reset when reaching CLOCK_RATIO

  initial begin
    counter <= 0;
    sync <= 0;
  end

  always @(posedge clk) begin
    counter <= counter + 1;

    if(counter == SYNC_OUT_CLOCK_RATIO) begin
      counter <= 0;
      sync <= ~sync;
    end
  end
endmodule

Hier clkist der Haupttakt und syncder geteilte Takt, der direkt aus der Platine ausgegeben wird. Jetzt gibt mir ISE den folgenden Fehler:

Place:1136 - This design contains a global buffer instance,
   <clock_deskew_0/BUFG_inst>, driving the net, <clk>, that is driving the
   following (first 30) non-clock load pins.
   < PIN: sync_apbinterface_0/pclk_test_select[15]_AND_253_o4.A4; >
   This is not a recommended design practice in Spartan-6 due to limitations in
   the global routing that may cause excessive delay, skew or unroutable
   situations.  It is recommended to only use a BUFG resource to drive clock
   loads. If you wish to override this recommendation, you may use the
   CLOCK_DEDICATED_ROUTE constraint (given below) in the .ucf file to demote
   this message to a WARNING and allow your design to continue.
   < PIN "clock_deskew_0/BUFG_inst.O" CLOCK_DEDICATED_ROUTE = FALSE; >

Was genau ist hier das Problem und wie kann ich es beheben?

Beachten Sie zusätzlich zu dem Fehler, nach dem Sie gefragt haben, dass Sie tatsächlich eine Funktion zum Teilen durch 21 haben, wenn SYNC_OUT_CLOCK_RATIO 20 ist. Auch wenn Sie dies bereits bemerkt haben, ist es möglicherweise verwirrend für alle, die Ihren Code lesen müssen.

Antworten (3)

Ihr clkPin treibt einige Nicht-Takt-Pins an (LUT-Eingänge, wie es aussieht). Das ist fast immer eine schlechte Idee.

Öffnen Sie Ihr Design im Technologie-Viewer und sehen Sie sich die in der Protokolldatei (ist die erste) aufgeführten "Nicht-Takt-Ladestifte" an < PIN: sync_apbinterface_0/pclk_test_select[15]_AND_253_o4.A4; >und sehen Sie, ob Sie herausfinden können, warum eine LUT den CLK-Eingang verwendet.

Wenn sich herausstellt, dass alles in Ordnung ist und Sie dies aus irgendeinem Grund wirklich tun möchten, und Sie dies gerne vor einer bellenden Meute von Ingenieuren rechtfertigen, wenn alles schief geht, können Sie den Fehler wie unter beschrieben ausschalten Ende der Fehlermeldung.

Im Allgemeinen sollten Sie solche Trennlinien nicht schreiben. Sie erstellen ein Taktsignal aus Logik, was, wie ISE Ihnen sagt, keine empfohlene Designpraxis ist. Sie verbrauchen nicht nur (oft knappe) Clock-Routing-Netze, sondern können auch mit zittrigen, fehlerhaften Clocks enden, wenn die Logikblöcke in ihren nächsten Zustand übergehen.

Beispiele (in VHDL ziehe ich es Verilog vor, aber es ist ein einfaches Beispiel)

zB 1: wie man es NICHT macht (eine Uhr aus logischen Ausgängen erstellen):

signal counter: integer range 0 to 999;
signal slowclk: std_logic;

gen_slowclk: process(clk, rst)
begin
    if rising_edge(clk) then
        if counter = 0 then
            slow_clk <= not slow_clk;
            counter <= counter'high
        else
            counter <= counter - 1;
        end if;
    end if;

    if rst = '1' then
        slow_clk <= '0';
        counter = counter'high;
    end if;
end process;

use_slow_clk: process(slow_clk, rst)
begin
    if rising_edge(slow_clk) then
        -- ...
    end if;

    if reset = '1' then
        -- ...
    end if;
end process;

Dies erzeugt einen slow_clk, der 1000-mal langsamer als der Haupttakt ist, und verwendet dann dieses slow_clk-Signal als Takteingang in einem anderen Prozess. Es ist ein Beispiel dafür, wie man Dinge nicht tun sollte. Wenn Sie Ihre RTL untersuchen, sehen Sie, dass die Ausgabe der Logik in die Takteingänge der FFs im Prozess use_slow_clk geht, was schlecht ist.

Was Sie stattdessen tun sollten, ist das Erstellen von Taktfreigaben. Sie steuern Ihre gesamte Logik mit dem ursprünglichen (schnellen) Takt und erzeugen dann ein Taktaktivierungssignal. Die meisten FPGAs haben Flip-Flop-Grundelemente mit Taktaktivierungseingängen, und genau deshalb würden Sie auf diese Weise entwerfen.

zB 2: Taktfreigaben verwenden (empfohlener Weg):

signal counter: integer range 0 to 999;
signal slow_ce: std_logic;

gen_slow_ce: process(clk, rst)
begin
    if rising_edge(clk) then
        if counter = 0 then
            slow_ce <= '1';
            counter <= counter'high
        else
            slow_ce <= '0';
            counter <= counter - 1;
        end if;
    end if;

    if rst = '1' then
        slow_ce <= '0';
        counter = counter'high;
    end if;
end process;

use_slow_ce: process(clk, rst)
begin
    if rising_edge(clk) then
        if slow_ce = '1' then
            -- ...
        end if;
    end if;

    if reset = '1' then
        -- ...
    end if;
end process;

Wenn Sie die RTL dieser Art von Konstruktion untersuchen, werden Sie sehen, dass alle FFs dasselbe Taktsignal verwenden, und das auf einem Taktnetz bereitgestellt wird. Das hinzugefügte @if slow_ce = '1'@ wird vom Synthesizer erkannt und instanziiert ein FF mit einer Taktfreigabe; dies ist ein Signal, das dafür ausgelegt ist, mit Logik gesteuert zu werden und das FF sauber zu gaten.

In beiden Beispielen wird die Logik in @use_slow_*@ mit derselben Frequenz ausgeführt (1/1000 des Haupttakts), aber im zweiten Fall haben Sie nur ein Taktnetzwerk und nutzen die in Ihrem FPGA vorhandenen Taktfreigaben , was zu besserer Synthese, besseren Uhren und einfacherem Timing-Closure führt. Dies führt zu gesünderen FPGA-Designs, was zu zufriedenen FPGA-Designern führt. :-)

Warum sollte die Verwendung eines hochfrequenten Takts mit "niederfrequenten" Taktgebern zu einem einfacheren Timing-Schließen führen? Bedeuten Sie, dass ein multicycle_path für alle FFs definiert ist, die die Taktfreigaben mit "niedriger Frequenz" verwenden? Andernfalls erweitern Sie wissentlich die strengeren Timing-Anforderungen des Hochfrequenztakts auf die Logik, die mit der niedrigen Frequenz laufen sollte, was das Gegenteil einer Erleichterung des Timing-Schließens bewirkt ... Natürlich stimme ich der Notwendigkeit zu, das globale Taktungsnetzwerk zu verwenden für alle Taktsignale.

Vielleicht gibt es ein Problem mit den beiden gleichzeitigen Zuweisungen an counter. Sehen Sie, ob das Ändern Ihres alwaysBlocks hier hilft:

  always @(posedge clk) begin
    if(counter == SYNC_OUT_CLOCK_RATIO) begin
      counter <= 0;
      sync <= ~sync;
    end else begin
      counter <= counter + 1;
    end
  end