Wie kann ein einzelner Ausgangsimpuls von einem langen Eingang auf Altera effizient implementiert werden?

Ich habe eine schnelle Uhr und einen Schalter namens "bereit". Wenn der Schalter umgelegt wird (bereit geht auf HIGH), möchte ich, dass der Ausgang pcEn einen Impuls erzeugt, der nur einen Taktzyklus dauert. pcEn wird nur dann einen weiteren Impuls ausgeben, wenn ready das nächste Mal wieder auf HIGH geht.

Der folgende Code simuliert korrekt, ist aber leider nicht synthetisierbar. Beachten Sie, dass Platz eine wichtige Überlegung ist, daher habe ich mich gefragt, ob es möglich ist, dies ohne Verwendung einer Zustandsmaschine (die viele Logikelemente verwendet) zu implementieren.

module control
(
    output logic pcEn,
    input clock, ready
);

always_ff @(negedge clock)
    pcEn <= 1'b0;

always_ff @(posedge ready)
    pcEn <= 1'b1;

endmodule
Es ist im Allgemeinen nicht wahr, dass "eine Zustandsmaschine ... viele logische Elemente verwendet". Tools codieren sie meistens in One-Hot und verwenden ein Register pro erreichbarem Zustand. Die Steuerlogik wird von Datenpfad-Multiplexern, Addierern usw. in den Schatten gestellt.
Ich denke schon. Im Moment verbraucht mein Addierer Tonnen von Logikelementen. Gibt es eine Möglichkeit, diese Ressourcen in den Arbeitsspeicher oder in eingebettete Multiplikatoren umzuleiten (in meinem Fall sind sie billig)?
Es gibt keine Addierer darüber, also ist es schwer zu sagen
Ah, ich denke nicht, dass es angebracht ist, meinen Addierercode auch hier zu posten, da er für die Frage nicht relevant ist. Es ist jedoch nur ein einfacher Addierer ohne Ein- oder Austrag. Im Grunde ein Haufen XOR-Gatter.
@geft: Ich würde vorschlagen, eine Frage zum separaten Verringern der Größe des Addierers zu stellen (obwohl, wenn Sie gerade y <= a + b getan haben, wahrscheinlich nicht viel zu tun ist, es sei denn, Sie haben andere besondere Umstände!)

Antworten (3)

Meine übliche Technik besteht darin, einen zweistufigen Synchronisierer zu implementieren, um die asynchrone Eingabe in den Zeitbereich der Uhr zu bringen, und dann ein weiteres Flip-Flop als Flankendetektor zu verwenden. Abhängig von der Logik, die Sie in der letzten Anweisung verwenden, können Sie steigende Flanken, fallende Flanken oder beides erkennen.

module control
(
    output logic pcEn,
    input clock, ready
);
    reg r1, r2, r3;

    always @(posedge clock) begin
        r1 <= ready;    // first stage of 2-stage synchronizer
        r2 <= r1;       // second stage of 2-stage synchronizer
        r3 <= r2;       // edge detector memory
    end

    pcEn <= r2 && !r3;   // pulse on rising edge
endmodule
Danke schön. Wie ist dies im Vergleich zu der modifizierten Antwort von shuckc oben? Es scheint mehr Logikelemente als nötig zu verwenden.
Es verwendet 3 FFs und eine LUT. Dies ist das Minimum, das erforderlich ist, um eine asynchrone Eingabe korrekt zu verarbeiten.
Ah ich sehe. Ich habe noch nie einen benutzt. Ich werde sehen, wie es geht.
Danke für die obige Antwort. Hier ist eine gute Referenz zum Pegel-zu-Puls-Konverter, die auch andere Implementierungen für die obige Logik erklärt.

Die übliche Formation für Toggle-to-Pulse ist in etwa so

module flip (output logic pcEn, input clock, input ready);
reg state;
always_ff @(posedge clock)
      state <= ready;
assign pcEn = state != ready;
endmodule

Wenn readyes extern angesteuert wird, lohnt es sich, es zu bereinigen, um es zuerst mit einer Taktflanke mit einer einzelnen Registerstufe auszurichten. Das Zurücksetzen ist nicht erforderlich. Wenn Sie den Ausgang zählen möchten , müssen Sie auch das Schalterprellen adressieren .

Um den Kommentar von Daves anzusprechen: geändert, um den Ausgang pcEn zu registrieren und bei steigender Flanke auszulösen.

module flip (output reg pcEn, input clock, input ready);
reg state;
always_ff @(posedge clock) begin
      state <= ready;
      pcEn  <= state != ready && ready;
end
endmodule

Geben Sie hier die Bildbeschreibung ein

Scheint nicht zu funktionieren, da der Zustand gleich bereit ist. Wenn simuliert, schaltet pcEn während des Flankentriggers nur gleichzeitig auf HIGH und LOW um.
Dies ist eine falsche Antwort; Es erzeugt einen Impuls sowohl an steigenden als auch an fallenden Flanken des Eingangssignals. Außerdem ist der Ausgangsimpuls weniger als einen Takt breit.
Selbst mit der Bearbeitung behandeln Sie die asynchrone Eingabe immer noch nicht readyrichtig. Es besteht die Möglichkeit von Setup/Hold-Time-Verletzungen am letzten Flip-Flop, wodurch es in einen metastabilen Zustand versetzt wird.
@DaveTweed Danke, ich wusste nicht, dass es ein Problem sein könnte.

Dies scheint Xilinx zu empfehlen, was nicht allzu weit von Dave Tweeds entfernt ist:

(* ASYNC_REG = "TRUE" *) reg     state;
(* ASYNC_REG = "TRUE" *) reg     statemeta;
reg                              reloadRegmeta  = 1'b0;

# -> for negative edge    assign pcEn = state | (~reloadRegmeta);
assign pcEn = state && (~reloadRegmeta);
always @(posedge S_AXI_ACLK) begin
    statemeta     <= ready;
    state         <= statemeta;
    reloadRegmeta <= state;
end