Logik ODER zurücksetzen und löschen?
Ich versuche, die beste Vorgehensweise für die Implementierung eines Zurücksetzens (asynchron angewendet, Synchronisierung gelöscht) und einer eindeutigen Eingabe herauszufinden. Ich habe einen Prozess, der von einem logisch abgeleiteten Takt (NCO) ausgeführt werden muss, der code_clk heißt, langsamer, aber synchron zum tatsächlichen clk. Der Prozess beinhaltet ein lineares Rückkopplungsschieberegister, das auf alle Einsen zurückgesetzt werden muss, um eine Codegenerierungssequenz zu starten, nachdem das Zurücksetzen aufgehoben wurde. Während des gesamten Betriebs sollte der Prozess jedoch auch auf alle Einsen zurückgesetzt werden, wenn ein neuer Satz von Abgriffen (T1 und T2) für die Ausgabe ausgewählt wird, natürlich um die Codegenerierungssequenz zurückzusetzen und sicherzustellen, dass der neue Code mit dem neuen gültig ist Wasserhähne. Dies geschieht mit einem separaten, synchronen CLR-Eingang, der für einen einzelnen Systemtaktzyklus hoch gehalten wird, während die Abgriffe bewegt werden.
Hier ist mein Code:
process(code_clk, reset, clr)
begin
if(reset='0' or clr='1') then
-- EARLY LFSR
EG1(1 to 10) <= (others => '1');
EG2(1 to 10) <= (others => '1');
early_code <= '0';
delay_os <= '0';
elsif(falling_edge(code_clk)) then
if(delay_os='0') then
-- LFSR feedbacks for early code
EG1(2 to 10) <= EG1(1 to 9);
EG2(2 to 10) <= EG2(1 to 9);
EG1(1) <= EG1(3) xor EG1(10);
EG2(1) <= EG2(2) xor EG2(3) xor EG2(6) xor EG2(8) xor EG2(9) xor EG2(10);
early_code <= EG1(10) xor EG2(T1) xor EG2(T2); -- C/A output of early LFSR
else
-- delay of code chips commanded - do not shift this time
delay_os <= '0';
end if;
late_code <= early_code; -- one half chip delay from prompt code
elsif(rising_edge(code_clk)) then
prompt_code <= early code; -- one half chip delay from early code
end if;
end process;
Die bedingte if (reset = '0' oder clr = '1') springt mich als schlechten Stil an. Es scheint nur eine dieser Situationen zu sein, in denen die Synthese unnötige Logik oder Zeitverzögerungen erzeugt, weil der Rücksetzpfad nicht so einfach ist. Kann ich das machen oder soll ich etwas anderes ausprobieren? Das Löschen muss sofort erfolgen, damit ich entweder den Prozess von der Systemuhr ablaufen lassen muss oder etwas anderes. Wird dies als gute Praxis angesehen?
Antworten
Ihre Instinkte für die Bedingung sind richtig. Einige Synthesewerkzeuge verstehen möglicherweise, was Sie versuchen, aber viele werden es nicht tun, da das, was Sie geschrieben haben, kein etabliertes Muster ist, sodass die Werkzeuge möglicherweise nicht so schließen, wie Sie es möchten. Der Standard (wenn es so etwas gibt) / akzeptierte Art zu schreiben, was Sie erreichen wollen, lautet wie folgt:
process(clk, reset)
begin
if reset = '1' then -- async reset
-- your code here
elsif Rising_edge(clk) then
if sync_clr = '1' then -- sync clear
-- your code here
end if;
end if;
end process;
Ich stelle fest, dass Ihr Reset aktiv niedrig ist, was im FPGA eher verpönt ist (mehr mit der Lesbarkeit des Codes als mit tatsächlichen Architekturproblemen).
Aber warte! Warum ist das eigentlich wichtig?
Dies hängt von der individuellen Architektur des verwendeten FPGA ab. Unten finden Sie einen Ausschnitt aus dem Blockdiagramm für ein adaptives Cyclone V-Logikmodul.
Wenn Sie sich die Register ansehen, sehen Sie, dass sie nur eine einzige Steuerung haben - CLR. Oben im Diagramm sehen Sie die Signale aclr [1: 0], die in das ALM eingehen . Wenn Sie auf einen asynchronen Reset schließen, wird dies festgelegt. Beachten Sie, dass dieses ALM 4 Register hat, aber nur 2 Rücksetzsignale, die von den Paaren gemeinsam genutzt werden. Dies hat Auswirkungen darauf, wie viele ALMs verwendet werden.
Sie können auch ein synchrones Löschsignal ( sclr ) und ein synchrones Lastsignal ( syncload ) im ALM sehen. Diese werden von allen 4 Registern gemeinsam genutzt. Diese Schaltungen werden verwendet, wenn sie im Code abgeleitet werden. Das Diagramm ist detailliert genug, um zu verstehen, wie die Signale funktionieren.
sclr soll hoch aktiv sein. Es wird invertiert und mit Daten UND-verknüpft, die den D-Eingang der Register speisen. Das heißt, wenn hoch, wird 0 dem D-Eingang zugeführt und Q wird beim nächsten Taktzyklus auf 0 aktualisiert.
syncload steuert einen Multiplexer an, der entweder die Ausgänge der LUTs oder datae0 auswählt, die außerhalb des ALM entstehen.
Beachten Sie, dass es keine asynchrone Menge gibt. Wenn Sie dies geschrieben haben, können die Tools dies nicht an die Gerätearchitektur anpassen und stattdessen mithilfe von LUTs implementieren. Dies gilt für jedes Steuerelement, das nicht Teil der Gerätearchitektur ist.
Xilinx hat ein Whitepaper, das dies ausführlicher erklärt: https://www.xilinx.com/support/documentation/white_papers/wp275.pdf