Hallo, ich habe gerade ein Verständnisproblem. Es geht um NoC-Router, die jeweils 3 Ein- und 3 Ausgänge haben (jeweils Lokal, X und Y) und als Ringe verschaltet werden. Die Schnittstelle besteht aus valid, addr, data, ready. Ein Datenwort soll den Router in einem Takt passieren können und bis zu drei Worte gleichzeitig. Routing findet in 4 Schritten statt: a) ich baue aus den Adressen am Eingang einen Requestvektor (3x3 = 9 Bit) zusammen, der angibt, welcher Eingang auf welchen Ausgang geroutet werden möchte; b) ich aus dem Requestvektor einen Grantvektor (ebenfalls 9 Bit) zusammen, der angibt, welcher Eingang auf welchen Ausgang geroutet werden kann; c) mit der nächsten Taktflanke werden die Eingangswerte in Ausgangsregister übernommen, wenn der Ausgang bereit ist (d.h. die alten Werte akzeptiert) d) die Ausgangsregister werden auf die Ausgänge gegeben, wenn sie gültige Werte enthalten. Der angehängte Code simuliert korrekt, aber die Synthese findet kombinatorische Schleifen für xo_ready und yo_ready. Wenn der Ausgang die Daten nicht abnehmen kann, dann kann der Eingang die Daten ebenfalls nicht abnehmen. Da aber der letzte Ausgang mit dem ersten Eingang verbunden ist, gibt das zwangsweise eine kombinatorische Schleife. Ich muss ja alle auflaufenden Datenpakete gleichzeitig anhalten, wenn ein Ausgang sich entscheidet, in diesem Takt die Daten nicht abzunehmen. Und da stellen sich bei mir zwei Fragen: - Wo ist mein Denkfehler? - Was kann ich tun, um die Schleife wegzubekommen? Gruß, Svenska
Schau einfach mal die I/O-Signale an: Die werden teilweise kombinatorisch verarbeitet und dann direkt wieder ausgegeben, Z.B. in bedingter Form if .. .. li_ready <= xo_ready; end if; Verknüpfst Du nun ausserhalb ebenfalls li_ready und xo_ready, dann hast du eine komb.Schleife. Und das ist nur ein Beispiel von vielen Fallstricken in deinem Code.
Sigi schrieb: > Verknüpfst Du nun ausserhalb ebenfalls li_ready und > xo_ready, dann hast du eine komb.Schleife. Das ist mir klar. Nur muss ich das ja machen, um den gesamten Datenstrom gleichzeitig anzuhalten (sonst überrennen mir die hinten anstehenden Elemente das Register, weil sie noch nicht wissen, dass es vorne gerade nicht weiter geht). Durch den Algorithmus sollte es nicht möglich sein, dass ich tatsächlich alle Router gleichzeitig auf "X -> X" konfiguriere. (Ein gelegentlicher Deadlock wäre im Übrigen sogar akzeptabel.) Nur: Wie baut man sowas richtig? Sigi schrieb: > Und das ist nur ein Beispiel von vielen Fallstricken in > deinem Code. Magst du mir mehr dazu sagen?
Das ist wieder mal ein Beispiel für einen Code, der so verfasst ist, dass er funktionell bei Ausführung richtig arbeitet. Das tut er aber nur deshalb, weil er Annahmen über das Zeitverhalten des Simulators macht, speziell im Bezug auf Abfolge und Reihenfolge, sowie Exklusivität bei If-Thens. Bei VHDL ist es aber wichtig zu verstehen, daß der FPGA diesen Code niemals sieht und ihn auch nicht so abarbeitet. Der Synthesizer tut das und der baut logischerweise nur, was er in seinem Durchlauf "sieht". Anders, als ein Simulator, spielt er den Code aber nicht zeitlich ab, sondern interpretiert ihn statisch. Wenn also das Betreten eines IF-Then-Pfades dazu führt, dass Aktion 1 gemacht wird und Aktion 2,3,4 unterlassen werden, klappt das in der zeitlichen Untersuchung im Simulator bestens - hinsichlich der denkbaren Möglichkeiten ist das aber unvollständig. In VHDL reicht es nicht, nur den "Gutweg" zu beschreiben, sondern es müssen ALLE Fälle beschrieben werden. Da das implizit oft nicht geht, muss es explizit erfolgen. Heisst also: 1) Es müssen alle durch die Signalabfragen denkbaren Kombinationen besetzt werden, d.h alle Pfade müssen beschrieben werden. 2) In allen Pfaden müssen alle Signale die getrieben werden belegt werden. 3) Die Signale dürfen nur dort getrieben werden. Ein guter Weg, das Sicherzustellen ist, die Schaltung von hinten her zu beschreiben und sich zu Überlegen, wie die Bedingung aussieht, die einen Ausgang auf 1 schalten soll. So, wie es die meisten machen, von vorne und "ereignisgesteuert" durch das System zu denken, entstehen oft Widersprüche und Mangelbeschreibungen, die eben besagtes Zeitverhalten einer CPU benötigen um sie aufzulösen.
Jürgen S. schrieb: > Das ist wieder mal ein Beispiel für einen Code, der so verfasst ist, > dass er funktionell bei Ausführung richtig arbeitet. Deine Ausführungen sind ja richtig, aber so allgemein verfasst, dass ich daraus nichts ableiten kann. > weil er Annahmen über das Zeitverhalten des Simulators macht, > speziell im Bezug auf Abfolge und Reihenfolge, sowie Exklusivität bei > If-Thens Die Reihenfolge der if/elsif/elsif/endif-Ketten implementiert die Prioritäten. Da ist keine Annahme über das Simulatorverhalten drin (bzw. die generierte Schaltung ist sequentiell - soll sie auch sein). > In VHDL reicht es nicht, nur den "Gutweg" zu beschreiben, sondern es > müssen ALLE Fälle beschrieben werden. Deswegen steht am Anfang der Prozesse immer das Default-Verhalten ("input ready", "output not valid mit addr/data unbestimmt"). Das macht die Simulation einfacher zu lesen. Laut Dokumentation versteht Vivado den Wert '-' auch für die Synthese und kann damit optimieren. > 1) Es müssen alle durch die Signalabfragen denkbaren Kombinationen > besetzt werden, d.h alle Pfade müssen beschrieben werden. > 2) In allen Pfaden müssen alle Signale die getrieben werden belegt > werden. > 3) Die Signale dürfen nur dort getrieben werden. Ist - soweit ich das einschätzen kann - alles erfüllt. Kurz: Was ich aus den Antworten herauslese, ist "so macht man es nicht". Das hilft mir aber leider nicht weiter. Ich würde ja gerne wissen, wie man es richtig (oder zumindest nicht falsch) macht.
S. R. schrieb: > Ist - soweit ich das einschätzen kann - alles erfüllt. Soweit ich den Code überflogen habe, sehe ich das genauso. Dein Code ist Sauber ausgeschrieben und alle komb. Prozesse mit Default-Zuweisungen versehen (soweit erforderlich) bzw. die IFs mit ELSEs komplettiert. Da liegt also nicht der Fehler. Das Problem ist eben, dass Du Ausgangssignale per Kombinatorik direkt aus Eingangssignalen generierst. Übertragen auf einen FIFO, der kurz vorm überlaufen ist: 1. FIFO meldet READY=true 2. Die Nutzerkomponente setzt WRITE=true (+Data..) 3. FIFO setzt letzten Wert und meldet dann READY=false 4. Die Nutzerkomponente setzt daraufhin WRITE=false 5. FIFO setzt deshalb READY=true 6. etc. Und das alles im selben Takt. Lösung hier: READY wird registriert (FlipFlop) und liefert erst im nächsten Takt eine Antwort auf ein WRITE-Gesuch. Und genau das ist wahrscheinlich die Lösung für Dein Problem. (Aber eine algem. Lösung gibt's für solcherlei Probleme nicht, dazu können ja je nach Problem die verschiedensten Timing-Anforderrunben formuliert werden)
> Kombinatorische Schleife
Waaaas?
Der einzige, der das machen darf, ist Lothar Miller!
Auf gar keinen Fall schrieb: > Der einzige, der das machen darf, ist Lothar Miller! Mit ihm habe ich es mir wohl (versehentlich) verscherzt... jedenfalls hat er sich hier rausgehalten.
S. R. schrieb: > Mit ihm habe ich es mir wohl (versehentlich) verscherzt... Nönö, passt schon. > jedenfalls hat er sich hier rausgehalten. Naja, ich denke mir immer: "Dann muss da eben noch irgendwo ein Flipflop rein!" Aber das kann man so ja nicht schreiben, das hört sich so unausgegoren an... S. R. schrieb: > Ich muss ja alle auflaufenden Datenpakete gleichzeitig anhalten, wenn > ein Ausgang sich entscheidet, in diesem Takt die Daten nicht abzunehmen. > Und da stellen sich bei mir zwei Fragen: > - Wo ist mein Denkfehler? Diese Reaktion und Interaktion im "selben Takt". > - Was kann ich tun, um die Schleife wegzubekommen? Einen Takt mehr einfügen. Dann ist Platz für ein Flipflop. Aber das hilft dir jetzt konkret auch nicht weiter. Deshalb hatte ich einfach mal nichts geschrieben... ;-)
:
Bearbeitet durch Moderator
Lothar M. schrieb: >> - Was kann ich tun, um die Schleife wegzubekommen? > Einen Takt mehr einfügen. Dann ist Platz für ein Flipflop. Das ist genau der Punkt, den ich vermeiden wollte, aber wenn es nicht anders geht, dann muss es eben so. Ist besser als keine Antwort. Lothar M. schrieb: > Aber das hilft dir jetzt konkret auch nicht weiter. Deshalb hatte ich > einfach mal nichts geschrieben... ;-) Dann bin ich ja beruhigt. :-)
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.