Ich habe hier ein Design mit zwei Clockdomains (jeweils 25MHz) und will Daten hin und her schicken. Dazwischen hängt ein CPLD (XC9536XL). In einem FPGA würde ich ja einfach einen asynchronen FIFO benutzen, das geht hier leider nicht. Und einfach die Daten auf der neuen Clock einsynchronisieren, bring es auch nicht, da halt manchmal ein Bit fehlt oder doppelt ist. Was kann man da tun? Zwischen den Datenpaketen können die "doppelten" oder "fehlenden" Bits ruhig auftreten. Doch wie bekomme ich das hin? Ein RX_EN Signal hätte ich, um zu erkennen, ob die Datenbits gültig sind. Gibt es einen asynchronen FIFO als VHDL, der sich auch einem CPLD einsetzen lässt? Grüße, Martin
Hallo! Ich kenne zwar die Anwendung nicht, aber vielleicht ist es möglich aus zwei Clock Domains eine mit 25 MHz erzeugen? Einfach einen gemeinsamen Taktgeber benutzen? Gruß, fpga-dev
@ Martin W. (mawahh) >Ich habe hier ein Design mit zwei Clockdomains (jeweils 25MHz) und will >Was kann man da tun? Zwischen den Datenpaketen können die "doppelten" >oder "fehlenden" Bits ruhig auftreten. Doch wie bekomme ich das hin? Im Prinzip über ein Zwischenspeicher, der langsamer getaktet ist, und damit sicher doppelt getaktet werden kann. Also ein Art Schieberegister. >Gibt es einen asynchronen FIFO als VHDL, der sich auch einem CPLD >einsetzen lässt? Jain. Es gab mla ne schöne Seite von Xilinx zum Thema, ich kann sie aber leider nicht mehr finden :-( MFg Falk
Falk Brunner wrote: > Im Prinzip über ein Zwischenspeicher, der langsamer getaktet ist, und > damit sicher doppelt getaktet werden kann. Also ein Art Schieberegister. Kannst du das genauer erklären? Meinst du zwei Register, die immer abwechselnd mit den Eingangsdaten beschrieben werden, so dass man auf der Ausgangsseite in einem großen Bereich mit der Ausgangsclock abtasten kann, ohne setup- und holdtimeviolations zu bekommen? Gibt es VHDL davon?
@ Martin W. (mawahh) >Kannst du das genauer erklären? Meinst du zwei Register, die immer >abwechselnd mit den Eingangsdaten beschrieben werden, so dass man auf >der Ausgangsseite in einem großen Bereich mit der Ausgangsclock abtasten >kann, ohne setup- und holdtimeviolations zu bekommen? Gibt es VHDL >davon? So in der Art. Per Schieberegister wird der Datenstrom verlangsamt, meinetwegen auf 1/4 der ursprünglichen Taktfrequenz. Mit jedem 4. Takt, an dem neue Daten parallel in einem Zwischenregister zur Verfügung stehen, wird ein Steuersignal invertiert. Die Empfangsseite tastet das ab und erkennt einen Wechsel, woraufhin die Daten gefahrlos übernommen werden können. MfG Falk
Ok, ich habe das mal simuliert. Leider verursacht das Steuersignal auf der Empfängerseite jede Menge Setup-Time violations, wenn es zum falschen Zeitpunkt kommt, je nachdem wie die beiden Clocks halt grade zueinander laufen. Was kann ich denn dagegen tun? Die Daten scheinen korrekt übergeben zu werden. Oder kann ich das ignorieren und hoffen, dass es in der Realität läuft? Wenn das Steuersignal einen Takt später auf der Empfängerseite gesehen wird, geht es ja auch...
@ Martin W. (mawahh) >Ok, ich habe das mal simuliert. Leider verursacht das Steuersignal auf >der Empfängerseite jede Menge Setup-Time violations, wenn es zum >falschen Zeitpunkt kommt, je nachdem wie die beiden Clocks halt grade >zueinander laufen. Logisch,ist ja asynchron. Sowas ist schwer simulierbar. >Was kann ich denn dagegen tun? Die Daten scheinen korrekt übergeben zu >werden. Oder kann ich das ignorieren und hoffen, dass es in der Realität >läuft? Jain. Wie sieht deine Schaltung denn aus? Postem mal VHDL oder Schaltplan. > Wenn das Steuersignal einen Takt später auf der Empfängerseite >gesehen wird, geht es ja auch... Eben. MfG Falk
Die oben gepostete lösung ist aber auch nichts anderes, als ein asynchroner Fifo, nur eben per Hand. Das kann man schon sn machen, nur muss man die Steuersignale auch synchronisieren. Zum Abtasten würde ich mal lieber die 3fache Frequenz nehmen, das ist leichter überschaubar, beim simulieren, da es nur den Fall von 1+1 und 2+1 Latenzcklocks gibt, was bei Faktor 3 wieder nur einem Zieltakt entspricht.
Ich hab jetzt das hier gebaut. Es scheint zu funktionieren... -- select input flip flop select_i0 : PROCESS (RESET_N, RXCLK0) BEGIN IF (RESET_N = '0') THEN select_input0 <= '0'; ELSIF (RXCLK0'event AND RXCLK0 = '1') THEN IF (RXDV0 = '0') THEN select_input0 <= '0'; ELSIF (select_input0 = '0') THEN select_input0 <= '1'; ELSE select_input0 <= '0'; END IF; END IF; END PROCESS; -- ff1 0->1 ff0_1: PROCESS (RESET_N, RXCLK0) BEGIN IF (RESET_N = '0') THEN q0_0 <= '0'; q0_1 <= '0'; q0_2 <= '0'; q0_3 <= '0'; ELSIF (RXCLK0'event AND RXCLK0 = '1') THEN IF (select_input0 = '0') THEN q0_0 <= RXD0_0; q0_1 <= RXD0_1; q0_2 <= RXD0_2; q0_3 <= RXD0_3; END IF; END IF; END PROCESS; -- ff2 0->1 ff0_2: PROCESS (RESET_N, RXCLK0) BEGIN IF (RESET_N = '0') THEN q1_0 <= '0'; q1_1 <= '0'; q1_2 <= '0'; q1_3 <= '0'; ELSIF (RXCLK0'event AND RXCLK0 = '1') THEN IF (select_input0 = '1') THEN q1_0 <= RXD0_0; q1_1 <= RXD0_1; q1_2 <= RXD0_2; q1_3 <= RXD0_3; END IF; END IF; END PROCESS; -- latch RXDV0 latch_rxdv0_0 : PROCESS (RESET_N, RXCLK0) BEGIN IF (RESET_N = '0') THEN q0_rxdv <= '0'; ELSIF (RXCLK0'event AND RXCLK0 = '1') THEN q0_rxdv <= RXDV0; END IF; END PROCESS; latch_rxdv0_1 : PROCESS (RESET_N, TXCLK1) BEGIN IF (RESET_N = '0') THEN q1_rxdv <= '0'; ELSIF (TXCLK1'event AND TXCLK1 = '1') THEN q1_rxdv <= q0_rxdv; -- possible setup-time violation here! END IF; END PROCESS; -- select output flip flop select_o1 : PROCESS (RESET_N, TXCLK1) BEGIN IF (RESET_N = '0') THEN select_output1 <= '0'; ELSIF (TXCLK1'event AND TXCLK1 = '1') THEN IF (q1_rxdv = '0') THEN select_output1 <= '0'; ELSIF (select_output1 = '0') THEN select_output1 <= '1'; ELSE select_output1 <= '0'; END IF; END IF; END PROCESS; -- ff3 0->1 ff0_3: PROCESS (RESET_N, TXCLK1) BEGIN IF (RESET_N = '0') THEN TXD1_0 <= '0'; TXD1_1 <= '0'; TXD1_2 <= '0'; TXD1_3 <= '0'; TXEN1 <= '0'; ELSIF (TXCLK1'event AND TXCLK1 = '1') THEN IF (select_output1 = '0' AND q1_rxdv = '1') THEN TXD1_0 <= q0_0; TXD1_1 <= q0_1; TXD1_2 <= q0_2; TXD1_3 <= q0_3; ELSIF (select_output1 = '1' AND q1_rxdv = '1') THEN TXD1_0 <= q1_0; TXD1_1 <= q1_1; TXD1_2 <= q1_2; TXD1_3 <= q1_3; ELSE TXD1_0 <= '0'; TXD1_1 <= '0'; TXD1_2 <= '0'; TXD1_3 <= '0'; END IF; TXEN1 <= q1_rxdv; END IF; END PROCESS;
Ich lese hier angestrengt mit, verstehe aber immer noch nicht das grundsätzliche Problem. Wir haben doch einfach einen Datenbus mit einer Art von data valid? Das wäre doch zu hehandlen, wie ein ganz "schnödes" asynchrones Bus-Interface, oder kapiere ich da was nicht ?
Für den genannten CPLD hat mawahh keine FIFO-Implementierung gefunden, die asynchrone Schreib- und Lesetakte erlaubt... @falk: Das hier? XAPP051 - Synchronous and Asynchronous FIFO Designs (PDF) http://www.xilinx.com/support/documentation/application_notes/xapp051.pdf Device (XC4000) passt zwar net, aber immerhin gehts hier um CPLDs. Intern wird leider dual-ported RAM benutzt, was der XC9536XL nicht besitzt.
Das FIFO kann man sich in der üblichen Weise selber bauen, es muss nur sichergestellt werden, daß beide Seiten die für sie gültigen Signale der anderen Seite einsynchronsieren. Das kann man sogar beliebig dämlich und redundant formulieren - solange man eine RTL-optimierung drüberlaufen lässt, kommmt immer dasselbe bei raus, habe ich gemerkt :-)
Flancter ist ein Stichwort. Das Problem: Wie setze ich ein Flag in einer Clock-Domain und lösche es in der anderen? mfg, Stefan.
Statisch : Ein asynchrones Schaltwerk, das beide Takte im Auge hat und per Vorrang entscheidet, ob gelöscht wird, oder nicht. Beide Löschpegel müssen mindestens 2 Takte bezogen auf den gegenüber anliegen. Massgeblich für das Flipflop ist das so ermittelte set/reset, sowie das Ergebnis einer Vorrangschaltung, die den durchschaltet, der zuletzt getaktet hat. Im Kollisionsfall setzt sich so der druch der zuletzt noch setrzen/resetten wollte. Kann man aber auch anders einstellen. Dynamisch : Indem Du die Löschinfo als einen Impuls überträgst, der lang genug ist, um von der Zieldomain, die das Flag verwaltet, erkannt zu werden. Die Zieldomain nimmt dann den Resetwunsch entgegen und taktet das Ergebnis synchronisiert wieder raus. Macht, wenn man es korrekt programmiert genau 3 Takte Delay, bis der Generationsprozess das fallende Flag sieht. Wenn der Verwaltungsprozess auch resetten (und nicht nur setten) kann, muss dessen Reset auch verzögert werden und gfs ein Semaphor entscheiden, wer auf dem Flag arbeiten darf.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.