Hallo,
sorry für den wenig aussagekräftigen Thread-Titel aber ich tue mir
schwer, das Problem kurz zu beschreiben.
Ich habe in meinem Virtex 5 Design Probleme, die sehr nach
Timing-Problemen aussehen: Dinge, die in der Simulation funktionieren
verhalten sich in der HW anders, bei manchen Syntheseergebnissen kommt
es sogar zu einem vollkommen falschen Verhalten einer bestimmten State
Machine, das ich mir nur mit einem Timing-Problem erklären kann, das
dazu führt, dass die einen FFs in den Folgezustand gehen und die anderen
nicht.
Das ganze tritt am Übergang zwischen zwei Clock-Domänen auf, allerdings
sind diese nicht komplett asynchron sondern beide haben 125 MHz
Taktfrequenz nur ist die eine mittels PLL aus der anderen abgeleitet.
Diese zwei Taktdomänen existieren schon lange problemfrei im Design und
bisher hatte ich keine Probleme, von der einen zu anderen ohne
Synchronisation Daten zu schieben. Insbesondere dachte ich, dass das
Synthesetool das durchaus berücksichtigt und eben den notwendigen margin
für zusätzlichen Jitter durch die PLL sowie anderes Taktnetzwerk usw
einrechnet. Der Timing-Report sagt jedenfalls, dass alle Constraints
erfüllt sind.
Habe ich da was falsch verstanden bzgl Taktdomänen und via PLL
abgeleiteten Taktdomänen. Ich hab da nämlich noch einige andere
langsamere Taktdomänen (62.5 MHz), die aus derselben PLL kommen und die
ich bisher auch als synchron zur 125 MHz Taktdomäne gesehen habe. Es
wäre schlecht für mich, wenn die auch ein Problem haben.
Danke fürs Lesen und lG
Matthias
In deinem Fall sollten alle Uebergaenge zwischen clock domains von den
Tools beruecksichtigt werden. Durch die Benutzung der PLLs sind die
Beziehungen zwischen den Clock Domains ja fest vorgegeben.
Wenn ein Design in der Simulation funktioniert, aber nicht in der
Wirklichkeit, dann wuerde ich zu allererst ueberpruefen, ob auch
wirklich ueberall alle sensitivity lists komplett und korrekt sind.
Aus welchem Grund benutzt du so viele verschiedene Takte? Gibt es nicht
vielleicht doch eine Moeglichkeit, einen gemeinsamen Takt zu verwenden?
Um die vielen Takte komme ich wahrscheinlich nicht herum, ich habe eine
PCIe Anbindung über den Endpoint Block Plus und brauche für die
Ansteuerung diverser externer Koponenten Takte mit 62.5 MHz, teilweise
auch mit 180 Grad Phasenversatz. Bisher hatte ich damit keine Probleme.
Jetzt soll auch noch der DDR2 auf dem Board an das ganze ran und der
braucht neben den 125 MHz und den 62.5 MHz die ich habe auch noch einen
125 MHz + 90 Grad Phase und einen 200 MHz Takt. Das ganze kann ich noch
mit einer PLL erzeugen.
Und jetzt geschieht es eben, dass das ganze solange ordentlich läuft,
wie ich nichts aus dem DDR2 auslesen, wenn von dem aber das
rd_data_valid Signal kommt (das gültige Lesedaten anzeigt) dann gibt es
Probleme, im nicht so dramatischen Fall kommt das erste der beiden
gelesenen Wörter nicht im entsprechenden Register an aber die FSM macht,
was sie soll, im dramatischen läuft die FSM "Amok" und das gesamte
System hängt.
Soweit zumindest der Befund nachdem ich mir die Signale auf den
Logikanalysator hinausgeführt habe.
Irgendwie kann es, soweit ich es derzeit sehe, nur ein Timing-Problem
von diesem rd_data_valid Signal sein.
Das ganze passiert überall in getakteten Prozessen, darum glaube ich
nicht, dass es an vergessenen Signalen in der Sensitivity List liegt,
aber ich werde es natürlich checken.
Lg
Matthias
Um es noch ein wenig klarer zu machen: Die FSM die Amok läuft hängt am
PCIe und benutzt den von dort ausgegebenen 125 MHz Takt, das DDR2
Interface benutzt einen 125 MHz Takt der in der PLL mit aus dem Takt vom
PCIe Endpoint erzeugt wird. Das sind die beiden Taktdomänen, zwischen
denen das Problem auftritt.
Lg
Matthias
Das eine ist ein Takt, der ueber das Interface rein kommt, der andere
kommt (ueber eine PLL) aus einem lokalen Oszillator?
Das heisst dann also, dass die Phasenbeziehung und die Unterschiede in
der Frequenz vollkommen unbekannt sind? In diesem Fall kommst du um eine
aufwendige Synchronisierung mittels eines dual-port-dual-clock-FIFO
wahrscheinlich nicht herum. Ausserdem solltest du darauf achten, dass
alle Eingaenge in den FPGA auch mit INPUT bzw. OUTPUT - constraints
belegt sind, sowie die IO-Fliflops direkt an den Eingaengen auch
wirklich benutzt werden.
@ Matthias (Gast)
>Um es noch ein wenig klarer zu machen: Die FSM die Amok läuft hängt am>PCIe und benutzt den von dort ausgegebenen 125 MHz Takt, das DDR2>Interface benutzt einen 125 MHz Takt der in der PLL mit aus dem Takt vom>PCIe Endpoint erzeugt wird. Das sind die beiden Taktdomänen, zwischen>denen das Problem auftritt.
Tja, und wenn der PCIe Takt jittert, dann ist die Phasenlage alles
andere als konstant. Und er TUT jittern, vor allem weil er mittels
Spread Spectrum erzeugt wird.
-> Ergo Die beiden Taktdomänen müssen als asynchron betrachtet werden.
-> Asynchrones FIFO.
MFG
Falk
Danke für die Antworten. Ich habe inzwischen folgendes gemacht: Ich habe
einen Satz FFs, die ich schon vorher zur Behebung von Timing-Problemen
am Lese-Interface dazwischen (sozusagen pipelined) reingehängt habe, von
der steigenden Taktflanke (auf der der Rest läuft) auf die fallende
Taktflanke umgehängt, das Ergebnis war sehr schön, alles hat perfekt
funktioniert (min. 4 mio mal Schreiben/Auslesen ohne einen einzigen
Fehler). Die Ursache des Problems dürfte also klarer werden. Jetzt muss
ich mir noch klar werden, wie ich damit umgehe, immerhin gibts da ja
noch diverse andere Taktdomänen, die zwar in allen Syntheseläufen bisher
problemlos funktioniert haben aber die dasselbe Problem haben ->
jitternde Clock am PCIe Interface trifft auf PLL gefilterter Clock im
innerern des FPGA.
LG
Matthias
@ Duke Scarring (Gast)
>Auch ein Grund auf mehrere Taktdomänen zu verzichten:
Geht manchmal nicht. ABER!
Man sollte die Anzahl der Schnittstellen zwischen den Domänen möglichst
gering halten. Und an den wenigen Stellen SEHR koneservativ arbeiten.
MFG
Falk
Was mich gewundert hat ist dass die Synthese das nicht erkennt und das
beim PAR entsprechend berücksichtigt. Ich habe jetzt bei den Constraints
beim PERIOD Constraint das INPUT_JITTER Keyword entdeckt, damit sollte
ich eigentlich die notwendige Information geben können. Aber wie kann
ich der Spread-Spectrum PCIe Clock einen Jitterwert zuweisen? Ich habe
noch nicht mal eine Angabe über das Spektrum der Clock gefunden.
LG
Matthias
Nachdem ich mich gestern mit meinem Chef dazu eingehend besprochen habe
hat er mir geraten, es mal mit einem DLL statt einer PLL zu versuchen,
weil diese den Jitter nicht rausfiltert. Siehe da, jetzt funktioniert
alles auch ohne Tricks wie die FFs auf der negativen Taktflanke
dazwischen zu schalten.
Ich muss das ganze erst noch weiter erproben, immerhin hatte ich je nach
Syntheselauf unterschiedliche Ergebnisse. Aber immerhin, das ist das
erste Design das vollständig funktioniert, inzwischen schon für einige
100 mio Schreib/Lesezugriffe auf den DDR2 fehlerfrei, also ganz so
schlecht kann es ja nicht sein.
LG
Matthias
Ich mache es immer folgendermaßen:
Ich habe eine Takt z.B. deine 125MHz. Den Takt gibst Du auf ein Register
das eine 1 enthält. Mit der steigenden Clockflanke schiebe ich die 1 um
eine stelle nach links weiter. Mit der fallenden Clockflanke frage ich
ab ob das Bit an der gewünschnten Stelle angekommen ist. Wenn das der
Fall ist führe eine gewisse funktion aus. Wenn Du nur ein Takt durch 2
teilen willst ist das Register halt nur zwei stellen lang. Zudem hälst
Du damit immer die Setuptime ein.
--**********************************************************
-- Ansteuerung des AD-Wandlers über die CS-Leitung *
--**********************************************************
process (CLK)
begin
if(CLK'event and CLK = '1') then
if(GATE = '0' or CLR = '1')then
CS_ADC <= '1';
else
CS_ADC <= S_REGA(0);
end if;
end if;
end process;
--**********************************************************
-- Irgendetwas ausführen *
--**********************************************************
process (CLK)
begin
if(CLK'event and CLK = '1') then
if(GATE = '0' or CLR = '1')then
Test <= '1';
else
if(S_REGA(3) = '1')then;
Test <= '0'; // Hier kann irgendeine Funktion ausgeführt
werden
end if;
end if;
end if;
end process;
--**********************************************************
-- Schieberegister für AD-Wandleransteuerung *
--**********************************************************
process (CLK)
begin
if(CLK'event and CLK = '0') then
if(CLR = '1' or GATE = '0') then
S_REGA <= "00000000000001";
else
S_REGA <= S_REGA(12 downto 0) & S_REGA(13); -- schieben
end if;
end if;
end process;
end structure;
> if(CLK'event and CLK = '0') then ...> if(CLK'event and CLK = '1') then ...> Zudem hälst Du damit immer die Setuptime ein.
Klar, denn das ist trotzdem nur 1 Taktdomäne, beschrieben mit
Clock-Enables.
Interessant wird es allerdings, wenn die Clock-Enables über größere
Flächen (an viele FFs) geroutet werden müssen...
Da kann es schnell mal vorkommen, dass ein globales Taktnetz besser
wäre.
@Johann
Es gibt keinen Grund dies mit unterschiedlichen Flanken zu tun, ganz im
Gegenteil, bei es kommt möglicherweise zu einen Halbierung der möglichen
Taktrate, weil Du nur mehr die halbe Taktperiode als Setup-Zeit hast.