Ich habe hier ein FPGA-Design, wo mehrere Entities auf eine gemeinsame Tabelle zugreifen (alles intern im FPGA) - einige nur lesend, einige nur schreibend. Der Zugriff auf die Tabelle wird von einem Round-Robin-Scheduler gesteuert, der nacheinander die Adressdaten abfragt und den entsprechenden Tabelleninhalt (24 bit breit) zurückliefert. Egal wie ich den Datenbus designe (shared oder dedizierte Leitungen zu den Lese-Entities, registered oder nicht), ich kämpfe immer mit Hold-Time-Violations - Setup slack ist reichlich da. Die Daten auf dem Bus müssen über den Chip verteilt an vielen Stellen verfügbar sein - irgendwie scheint das Problem damit zu tun zu haben... Das gesamte System läuft synchron über eine 50MHz Clock in einem Altera EP4CE40.
Rolf E. schrieb: > Egal wie ich den Datenbus designe Es gibt keine Tristate-Busse in einen aktuellen FPGA. Wenn du also mehrere Teilnehmer hast, die auf eine Ressource zugreifen wollen, dann bekommst du zwingend Multiplexer an den Adressen und den Daten. Und wenn du viele "Teilnehmer" hast, dann bekommst du riesige und langsame Multiplexer. > wo mehrere Entities auf eine gemeinsame Tabelle zugreifen (alles intern > im FPGA) Wie ist diese "Tabelle" realisiert? Als RAM-Block oder ist sie mit Logikzellen aufgebaut? > Die Daten auf dem Bus müssen über den Chip verteilt an vielen Stellen > verfügbar sein Hast du dir schon mal den RTL-Schaltplan und den Technologie-Schaltplan angeschaut? Passt das, was du dort siehst, zu dem, was du mit VHDL beschrieben hast?
Rolf E. schrieb: > ich kämpfe immer mit > Hold-Time-Violations - Setup slack ist reichlich da. Die Daten auf dem > Bus müssen über den Chip verteilt an vielen Stellen verfügbar sein - > irgendwie scheint das Problem damit zu tun zu haben... Ohne dein Design zu kennen, kann man nur sehr allgemeine Ausagen treffen. Hold Time Timing Violations sind ja ein "Hase und Igel-Problem". "Hase" ist die Clock und "Igel" sind die Daten. Der Igel ist schon da, während der Hase (die Clock) noch hastet. In einem sauberen, synchronen Design hat man an der Grenze zur maximalen Taktfrequenz meist eher mit Setup- als mit Hold-Violations zu tun, weil die Daten es im Vergleich zur Clock (die den Luxus der "Clock Netz-Autobahn" geniessen und keine kombinatorischen Delays kompensieren müssen) schwer haben, rechtzeitig anzukommen. Wenn Du also Hold-Time Violations hast, hast Du (nochmal: bei einem sauber synchronen Design) eher ein Luxusproblem (deine Daten sind zu schnell im Verhältnis zum Takt), das sich mit ein bißchen "eigentlich unnötiger, zusätzlicher Kombinatorik" im Datenpfad lösen lässt. Ich tippe aber eher darauf, dass das Design eben nicht sauber synchron ist und würde erst mal danach suchen (asynchrone Clocks, Clock Gating, ein Prozess auf der "falschen" Taktflanke, ...).
Ein großer Setup-Slack, aber dafür eine Holdtime-Violation, das bedeutet, dass das Zeitfenster, in dem die Daten stabil anliegen zu früh kommt (bezogen auf die aktive Clock-Edge). Die Daten sind also nicht zu langsam, sondern der Takt kommt zu spät. Das klingt eher nach einem Problem mit dem Taktnetz. Hast irgendwo Logik auf den Taktleitungen (Clock-Gates, Clock-Muxer) oder verwendest gar ein normales Netz für den Takt? Eine PLL/DCM mit falschem Phase-Shift? Probeweise könntest Du mal versuchen, im Ziel die Daten mit der umgekehrten Taktflanke zu samplen (also der fallenden vermutlich). Ist zwar nicht die bevorzugte Lösung, aber hilft vielleicht, das Problem zu analysieren.
Tatsächlich, jetzt dämmerts mir (und ich habe gestern nur die halbe Wahrheit erzählt, war schon spät): Es gibt zwei Clockdomains, und zwei Datenbusse. Jeder Busteilnehmer arbeitet umschaltbar auf zwei verschiedenen Clockdomains, dazu sind die Daten- und Clockleitungen gemultiplext. Das wird so synthetisiert, dass die Clocknetze nur bis zum Mux auf der "Autobahn" laufen und danach über ein normales Netz. Vielleicht hilft es, wenn ich den Clockmux so nahe am Ziel wie möglich platziere?
Lothar M. schrieb: > Rolf E. schrieb: >> dazu sind die Daten- und Clockleitungen gemultiplext. > Wie? -- Kombinatorisches Muxing von Daten und Clock entsprechend der gewählten -- Clockdomain -- mclk_0, mclk_1 sind globale clocks (laufen auf Clocknetzen) clk <= mclk_0 when domain = 0 else mclk_1; data <= data_0 when domain = 0 else data_1;
Rolf E. schrieb: > Kombinatorisches Muxing von Daten und Clock entsprechend der > gewählten Dazu verwendest Du besser die Clockmuxer-Primitive. Die sind glitchfree, und der Ausgang wird auch wieder auf ein Taktnetz geroutet.
Clock Multiplexing mit ALTCLKCTRL Dem Timing Analyzer muss man allerdings zusätzlich (mit exclusive clock groups, z.B.) auch sagen, dass immer nur eine Clock zur Zeit "scharf" ist.
> Dazu verwendest Du besser die Clockmuxer-Primitive. Die sind glitchfree, > und der Ausgang wird auch wieder auf ein Taktnetz geroutet. >Clock Multiplexing mit > ALTCLKCTRL Hab ich probiert: Der Ausgang von ALTCLKCTRL muss auf ein Taktnetz gerouted werden, sagt der Fitter. Leider gibts davon nicht genügend (bräuchte ca. 30 extra Taktnetze). >das sich mit ein bißchen "eigentlich unnötiger, zusätzlicher Kombinatorik" >im Datenpfad lösen lässt Das wäre meine Lieblingsvariante. Weiss jemand, wie ich das hinbekomme? Versuche a la data_1 <= data_in; data_2 <= data_1; data_out <= data_2; werden konsequent wegoptimiert, obwohl ich das eigentlich via "attribute keep", "attribute noprune" etc. verboten habe und "duplicate logic removal" ausgeschaltet ist.
Rolf E. schrieb: > (bräuchte ca. 30 extra Taktnetze) Ist so ein Design tatsächlich beherrschbar? Immer, wenn ich etwas "brauche", für das es keinen Hersteller gibt, frage ich mich, warum ich der Einzige mit diesem "Problem" bin... ;-)
Rolf E. schrieb: > Hab ich probiert: Der Ausgang von ALTCLKCTRL muss auf ein Taktnetz > gerouted werden, sagt der Fitter. Leider gibts davon nicht genügend > (bräuchte ca. 30 extra Taktnetze). Das will mir jetzt nicht so richtig einleuchten. Du hast >30 Clocks in deinem Design? Vielleicht beschreibst Du uns noch mal ausführlich, was Du da eigentlich treibst.
Rolf E. schrieb: > Versuche a la > data_1 <= data_in; > data_2 <= data_1; > data_out <= data_2; > werden konsequent wegoptimiert Das ist ja auch keine "Kombinatorik", sondern nur eine Umbenennung eines Signals. Denn letztlich kann der Router den Pfad von data_in über data1 und data2 nach data_out ja so "hintereinander" platzieren, dass dazwischen kein Elektron mehr Platz hat. Dann hat er seine Arbeit super gemacht! "Unnötige" Logik ist z.B. ein weiterer Multiplexer, der allerdings auch nicht statisch auf einen bestimmten Wert "geschaltet" sein darf. Sonst fliegt zu Recht auch der raus. > werden konsequent wegoptimiert, obwohl ich das eigentlich via "attribute > keep", "attribute noprune" etc. verboten habe und "duplicate logic > removal" ausgeschaltet ist. Du drehst da an Schrauben, wo man normalerweise nie zu drehen hat. Bestenfalls für wilde Hacks oder partielle Probleme sind diese Schalter nötig. Mir scheint, du hast da irgendein grundlegendes Designproblem...
Markus F. schrieb: > Das will mir jetzt nicht so richtig einleuchten. Du hast >30 Clocks in > deinem Design? Nein, nur 2 Clocks. Aber 30 Entities die entweder mit der einen oder mit der anderen Clock betrieben werden, und einzeln umschaltbar sein müssen. > Vielleicht beschreibst Du uns noch mal ausführlich, was Du da eigentlich > treibst. Das ist Teil eines Audio-Matrix-Switches, der 448x448 digitale Audiokanäle routen kann. Diese kommen über verschiedene Interfaces (z.B. MADI) mit je 64x64 Kanälen ins System bzw. wieder raus. Die zwei verschiedenen Clocks braucht es, weil für die Audiodaten zwei Clockdomains zur Verfügung stehen. Jedes Interface kann dynamisch entweder der einen oder der anderen Domain zugeordnet werden. Interfaces auf der selben Clockdomain kommunizieren direkt über besagten Bus; der Datenaustausch zwischen beiden Clockdomains erfolgt über einen Samplerate-Konverter (der allerdings nicht im FPGA implementiert ist, sondern in externer Hardware).
Lothar M. schrieb: > Ist so ein Design tatsächlich beherrschbar? > Immer, wenn ich etwas "brauche", für das es keinen Hersteller gibt, > frage ich mich, warum ich der Einzige mit diesem "Problem" bin... ;-) Ich glaube auch, er sollte nochmal überdenken, was er da baut! Ein 50MHz FPGA ist einfach nicht schnell genug, um soviele Eingangs-Domänen zu muxen. Man sollte es lieber einsynchronisieren und intern synchron muxen.
Markus W. schrieb: > Lothar M. schrieb: >> Ist so ein Design tatsächlich beherrschbar? >> Immer, wenn ich etwas "brauche", für das es keinen Hersteller gibt, >> frage ich mich, warum ich der Einzige mit diesem "Problem" bin... ;-) > > Ich glaube auch, er sollte nochmal überdenken, was er da baut! Ein 50MHz > FPGA ist einfach nicht schnell genug, um soviele Eingangs-Domänen zu > muxen. Man sollte es lieber einsynchronisieren und intern synchron > muxen. Nochmal: Es sind nur 2 Domänen. Die Challenge ist eher, dass es halt wahlweise die eine oder andere ist. Es ist definitiv auch beherrschbar, weil schon gebaut, geprüft, käuflich erwerbbar und für gut befunden: https://appsys.ch/mvr-64
o.k., danke. Hast Du jetzt einen dicken Clockmultiplexer gebaut, der jedem der Entities seine eigene Clock zuführt oder 30 kleine, die vor jedem dieser Entities die Umschaltung erlauben? Stehen die Clocks in irgendeinem konstanten (Takt-) Verhältnis zueinander?
> Hast Du jetzt einen dicken Clockmultiplexer gebaut, der jedem der > Entities seine eigene Clock zuführt oder 30 kleine, die vor jedem dieser > Entities die Umschaltung erlauben? Bis jetzt ist das ein dicker "30fach 2:1" Mux, jede Entity bekommt also entweder "clk_0" oder clk_1" und die Daten dazu synchron "data_0" bzw. "data_1". Weil nicht soviele Clocknetzwerke da sind, müssen sie über normale Signale getaktet werden - das ist auch kein Problem weil im Wesentlichen auf dieser Seite nur ein bisschen Bitschieberei getan werden muss. > Stehen die Clocks in irgendeinem konstanten (Takt-) Verhältnis > zueinander? clk_0 und clk_1 nicht, die Domains sind völlig unabhängig voneinander - beide Takte kommen von verschiedenen externen Geräten.
Und jedes der 30 Module kann unabhängig von jedem anderen seinen Takt umschalten. Bzw. muss es können? Oder laufen immer alle mit dem selben Takt? Oder wenigstens Gruppen davon?
Vancouver schrieb: > Probeweise könntest Du mal versuchen, im Ziel die Daten mit der > umgekehrten Taktflanke zu samplen (also der fallenden vermutlich). Ist > zwar nicht die bevorzugte Lösung, aber hilft vielleicht, das Problem zu > analysieren. Top Idee - Getan, synthetisiert, getestet und für gut befunden! Timing bestens, Setup- und Holdslack ausgeglichen, was will man mehr. Made my day!
Lothar M. schrieb: > Und jedes der 30 Module kann unabhängig von jedem anderen seinen Takt > umschalten. Bzw. muss es können? > Oder laufen immer alle mit dem selben Takt? Oder wenigstens Gruppen > davon? Ja, also rund 15 davon müssen unbedingt einzeln umschalten können, d.h. wahlweise aus clk_0 oder clk_1 betrieben werden. Die restlichen laufen entweder statisch immer auf der gleichen Clock oder werden in Gruppen umgeschaltet.
Rolf E. schrieb: > https://appsys.ch/mvr-64 interessant: "Swiss Design Made in Germany". Was sagt uns das?
Rolf E. schrieb: > Top Idee - Getan, synthetisiert, getestet und für gut befunden! Timing > bestens, Setup- und Holdslack ausgeglichen, was will man mehr. Made my > day! Wenn's so funktioniert ist's ja bestens. Gratuliere.
Allerdings hast du jetzt immernoch das Problem der Glitches beim Umschalten, wenn du rein kombinatorische Muxer verwendest. Vielleicht spielt das bei Audio keine Rolle (wenn man es nicht hört), aber sicherer wäre es trotzdem, die Glitches zu vermeiden. Es gab dazu mal ein richtig gutes Paper (von der SNUG, glaube ich), aber das finde ich nicht mehr. Vielleicht hilft die das hier weiter: https://www.eetimes.com/techniques-to-make-clock-switching-glitch-free/#
Ja, das ist klar. Umgeschaltet wird aber niemals im Betrieb, sondern geht immer mit einem Reset einher (in der Regel wird das Gerät auch vorher umverkabelt - daher kein Problem).
Audiomann schrieb: > interessant: "Swiss Design Made in Germany". Was sagt uns das? Zitat der Firmenwebseite: "Our products are developed in Switzerland and manufactured by our long-term partner in Germany who is responsible for PCB and mechanical assembly, QA and logistics."
Wenn du insgesamt nur 2 Takte hast, dann kannst du ja die Tabelle spiegeln und so für jede Taktdomaine eine Tabelle betreiben: alle Schreibzugriffe werden je Domaine einsynchronisiert und per MUX (z.B. mit Priorisierung) an die jeweilige Tabelle weitergeleitet. (ein Schreibzugriff schreibt immer in beide Tabellen!) Bei den Lesezugriffen sieht das MUXing einfacher aus: hier muss nur entweder aus Tabelle 1 oder Tabelle 2 gelesen werden. Und um Glitches zu vermeiden: Der Taktwechsel wird per Handshaking betrieben. Daraus lässt sich einfach ein Ready-Signal für Lese-Zugriffe ableiten, die das Lesen absolut sicher macht. Schreibzugriffe sind davon unabhängig. Das ganze funktioniert ohne Tricks wie positive oder negative Flanke nutzen etc.
Genau so ist es implementiert - zwei Tabellen, eine pro Clock. Aber der Tabellenzugriff ist gar nicht das Problem, wie ich jetzt gelernt habe. Sondern dass die "Leserclock" nicht direkt eine globale Clock (aus einem Clocknetz) ist, sondern aus deren zwei gemultiplext ausgewählt wird. Diese gemuxte Clock wird nicht auf ein Clocknetz (weil zuwenig vorhanden sind), sondern als normales (zu langsames) Datennetzwerk geroutet. Der Trick mit der fallenden Flanke sorgt quasi dafür, dass die Clock einen halben Zyklus schneller am Ziel ist, das geht genau auf. Setup-Violations bekomme ich trotzdem keine, weil null Kombinatorik dazwischen ist. Für diesen (und nur für diesen!) Pfad sieht es dann Setup-mässig so aus, wie wenn das Design mit 100MHz statt mit 50MHz laufen würde.
:
Bearbeitet durch User
Rolf E. schrieb: > Diese gemuxte Clock wird nicht auf ein Clocknetz (weil zuwenig vorhanden > sind), sondern als normales (zu langsames) Datennetzwerk geroutet. Genau das ist der Fehler im Konzept. Für meine Methode reichen zwei Clocknetze aus. Jeder "Teilnehmer" kann lesen/schreiben sowie den Takt auswählen (wenn dies nicht zentral geschieht), die Signale dazu werden in die jeweiligen Domainen einsynchronisiert und steuern dann die Logik und erhalten ggf einen Lesedatum zurück.
Und was ich noch vergessen habe: für meinen Ansatz brauchst du kein Clock-MUX, das MUXen geschieht hier nur auf der Ausgabeseite.
Geht nicht, weil die Takte und damit die Daten auseinanderlaufen. Bei nominell 48kHz Abtastrate werden die Daten in der einen Clcokdomain die Daten vielleicht mit vielleicht 48.001 kHz erzeugt bzw. erwartet, während in Domäne 1 ein anderer Clockmaster den Takt angibt und vielleicht mit 47.999 kHz arbeitet. Dadurch werden in jeder Clockdomain unterschiedliche Mengen an Daten (Samples) erzeugt bzw. erwartet, irgendwann gibt es buffer over/underruns aufgrund zuvieler oder fehlender Daten. Tontechniker kennen das: es äussert sich in periodischem Klicken im Signal.
Dass die Verschiebung um einen halben Clock ausreicht, halte ich für Zufall. Das mag für das erste abgetastete Datenbit helfen. Sowie mehrere FF hintereinander mit einem Nicht-Clock-Netz betrieben werden, haben die dann untereinander das Hold-Problem. Zu empfehlen wäre, mit einem einzigen und entsprechend höherem Clock zu arbeiten, z. B. 120 MHz. Dann den jeweiligen Eingangs-Clock und die Daten abtasten (letztere nach erkanntem 0-1-Wechsel des Clocks mit Verzögerung übernehmen oder umgekehrt). Erfordert allerdings einen eigenen Oszillator. Gibt es den oder wird auf die Eingangs-Clocks verwiesen?
Hmm, MHz oder kHz? Dezimal- oder Tausenderpunkte? Audio sind doch kHz, oder? In jedem Fall Clock UND Daten abtasten - keine Clock-Spielereien!
Würde man das bei Audio nicht eher so machen, dass man den Eingang erstmal interpoliert auf eine höhere Sample-Rate bringt und dann mit der gewünschten Ausgangs-Sample-Rate wieder runtersampelt?
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.