Forum: FPGA, VHDL & Co. Kombinatorische Schleife


von S. R. (svenska)


Angehängte Dateien:

Lesenswert?

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

von Sigi (Gast)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

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?

von J. S. (engineer) Benutzerseite


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

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.

von Sigi (Gast)


Lesenswert?

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)

von Auf gar keinen Fall (Gast)


Lesenswert?

> Kombinatorische Schleife

Waaaas?

Der einzige, der das machen darf, ist Lothar Miller!

von S. R. (svenska)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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
von S. R. (svenska)


Lesenswert?

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
Noch kein Account? Hier anmelden.