Forum: FPGA, VHDL & Co. taktbedinge Verzögerung von Signalen automatisch ermitteln und setzen


von K. L. (Gast)


Lesenswert?

Es geht um das Problem, dass bei Berechnungen von Daten aus 
unterschiedlichen Modulen die richtig verzögerten Kopien miteinander 
verrechnet werden müssen.

Nun habe ich das Problem, dass einige Rechenmodule sagen wir 6 Takte 
verzögert sind, andere 13 und wieder andere über 30. Um sie richtig zu 
verrechnen, müssen die langsamen entsprechend verzögert werden.

Wenn ich in einem Modul mal was ändern muss, weil das timing nicht 
getroffen wird und FFs hinzugefügt werden müssen, muss der Rest auch 
angepasst werden.

Wie macht man das am Besten?

Kann man das Delay irgendwie rausbekommen?

Die Synthese muss es ja auch kennen, wenn sie FFs hinzufügt oder 
verschiebt und muss den Rest dazu passend ändern.

Kann man das mit generate irgendwie dynmisch halten?

Momentan zähle ich in ModelSIM die Takte und passe es per Hand an. 
Problem: Mal vertut man sich und nix stimmt!

Gesucht ist eine automatisierte Lösung!

von daniel__m (Gast)


Lesenswert?

hi,

wenn sich häufig was änderst, dann würde ich vermutlich in jedem Modul 
ein begleitendes "Valid" durchleiten, welches dann am Ende ein Fifo 
bedient, welches hinter jedem Modul hängt. Diese Fifo ist so groß, dass 
der maximale Skew abgefangen werden kann. Sind alle Fifos nicht leer, 
kann ich Daten gesammelt auslesen und der weiteren Verarbeitungskette 
zuführen.

grüße

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Hallo Klaus,

es soll Menschen geben, die schreiben dazu eine Dissertation

http://diglib.uni-magdeburg.de/Dissertationen/2003/thoreinemann.pdf

Kapitel 4 und 6


Eine einfache Lösung gibt es nicht. Der FIFO Ansatz kann viele 
Ressourcen verbrauchen, denn jedes Modul muss soviel Stufen 
bereithalten, wie dass mit der größten Latenz zu dem es parallel 
geschaltet werden kann.

Tom

von Strubi (Gast)


Lesenswert?

Moin,

in VHDL geht das typischerweise nur über manuelle Klimmzüge und Delays, 
in MyHDL geht's etwas eleganter. Wenn es zur Laufzeit programmierbare 
Delays sein müssen, wird es hässlich, dafür flexibel (wenn die totale 
Latenz nicht so eine Rolle spielt).
Das kann man dann mit Microcode-Slots erledigen, die gegeneinander 
verschoben werden, wenn sich in der Pipeline was ändert, bzw. genau 
solche Buffer-Register steuern, wie von daniel_m beschrieben.
Das Problem mit solch in Logik instanzierten Mini-FIFOs ist schnell mal 
die Verstopfung, und damit das Zusammenbrechen der f_max, (drum 
"hässlich").

- Strubi

von J. S. (engineer) Benutzerseite


Lesenswert?

Thomas R. schrieb:
> es soll Menschen geben, die schreiben dazu eine Dissertation

Interessant. Wenigstens mal eine Dissertation mit Wert :-)

>FiFo
Ich verwende in der Tat meistens FiFos weil die RAMs bei den meisten 
Apps in ausreichender Zahl vorhanden sind. Die Steuerung erfolgt über 
variable delays. Etwas flexibler geht es mit einer halbautomatisierten 
Synthese in Excel, die die delay-Namen vergibt und die benötigten FFs 
einstellt. Heute ist das um so praktikabler, weil die Synthese unnötig 
verschwendete FFs in RAMs schieben kann.

von J. S. (engineer) Benutzerseite


Lesenswert?

Strubi schrieb:
> Wenn es zur Laufzeit programmierbare
> Delays sein müssen, wird es hässlich

Ich denke, es geht um die Entwicklung und nicht um die Laufzeit. Ich 
wüsste auch kaum Fälle, wo das flexibel bleiben müsste.

Trotzdem ist das ein Thema! Wie man das automatisch verifiziert, kann 
ich auch nicht sagen, ich speise immer ein erstes markantes Datum in 
ModelSim und prüfe das korrekte Weiterschalten. Man kann auch einen 
einzigen gültigen Wert in die pipeline schieben und beobachten, ob und 
wann er versiegt. Nur wenn alle timing delays stimmen, kommt der Wert 
valide durch.

von Schlumpf (Gast)


Lesenswert?

Vielleicht habe ich das Problem nicht ganz verstanden, aber wenn jedes 
dieser Module, welches Daten liefert, ein Valid-Signal mit ausgibt, 
welches einen Takt lang ist, dann muss das Modul, welches die Daten 
miteinander verrechnet, doch nur warten, bis das letzte der Module ein 
gültiges Datum abgeliefert hat und kann dann mit der Berechnung 
beginnen.

Sollte das schnellste der Module zwischenzeitlich schon ein neues Datum 
geliefert haben, dann muss dieses eben in ein FIFO abgelegt werden. Oder 
das Modul muss über einen Handshake-Mechanismus "ausgebremst" werden.

So muss also nur einmal die Schnittstelle auf ihr korrektes Timing 
überprüft werden. Wird ein Modul verlangsamt oder beschleunigt, dann 
funktioniert es ganz automatisch trotzdem noch.

Oder habe ich hier das Problem nicht richtig erfasst?

von Fpgakuechle K. (Gast)


Lesenswert?

Alternativvorschlag:
Die ermittlung der latentz würde ich in der Simulation mit den 
"passenden pattern machen. Beispielsweise, wenn 2 streams elementeweise 
multipliziert und anschliessend akkumuliert werden, dann würde ich einen 
Stream mit ab 1 steigenden Werten starten (1,2,3,4,5,...) und den 
anderen mit alles 0 außer einer '1' an einer einzelnen Position bspw 5. 
(0,0,0,0,1,0,0,...)

erscheint bei der Simulation eine 5 ist alles i.o. bei 4 muss eine 
Latenz eingefügt werde etc..

Das latenz wurde ich mit einem extra modul machen dem ich diese latenz 
per generic mitteile. dann hat es keinen großen aufwand. Man kann das 
generic auch in einem package festhalten, das macht spätere Änderungen 
einfacher. Dieses Modul kann man aus SRL16E macros (bei Xilinx Spartan) 
oder ähnlichen aufbauen, das sind schieberegister die bereits ein 
generic für die Länge des schieberegister haben (siehe 
http://www.xilinx.com/support/documentation/white_papers/wp271.pdf)


Also nicht "automatisch" sondern gezielt nach Ermittlung der notwendigen 
Verzögerung durch Simulation.

Wenn automatisch dann könnte man mit tcl scripten die netzliste (nach 
Synthese/mapping) durchparsen und so die FF im jeweiligen Pfad zählen. 
Das ging zumindest mit dem Cadance synthesetool. Bei xilinx könnte es 
sein das man die backannotierte EDIFF-Netzliste mit perl o.ä. bearbeiten 
muß.

Aber wie bereits betont, den Verzug gebe ich einer Ermittlung der 
Verzögerung in der Simulation.

MfG,

von Duke Scarring (Gast)


Lesenswert?

Schlumpf schrieb:
> Vielleicht habe ich das Problem nicht ganz verstanden, aber wenn jedes
> dieser Module, welches Daten liefert, ein Valid-Signal mit ausgibt,
> welches einen Takt lang ist, dann muss das Modul, welches die Daten
> miteinander verrechnet, doch nur warten, bis das letzte der Module ein
> gültiges Datum abgeliefert hat und kann dann mit der Berechnung
> beginnen.
Genau so mache ich das auch.
Ich habe mir dafür entsprechende Datentypen erstellt:
1
    type uint8_t is
2
    record
3
        value  : unsigned( 7 downto 0);
4
        enable : std_ulogic;
5
    end record;
6
    constant default_uint8_c : uint8_t := (
7
        value  => (others => '-'),
8
        enable => '0'
9
    );
10
    ....
Wenn ein Modul auf mehrere Werte warten muss, werden die mit ihrem 
enable gelatcht und wenn alle da sind, geht es los.
Das Ergebnis hat wieder ein enable, was für einen Takt lang '1' ist.

Ob die Latenzen passen, sehe ich in der Testbench. Ggf. kann man eine 
Assertion werfen, wenn die neuen Werte zu schnell kommen sollten.

Duke

von J. S. (engineer) Benutzerseite


Lesenswert?

Schlumpf schrieb:
> dann muss das Modul, welches die Daten
> miteinander verrechnet, doch nur warten, bis das letzte der Module ein
> gültiges Datum abgeliefert hat

Damit ist aber kein kontinuierlicher Betrieb möglich, weil das 
langsamtes Modul die anderen ausbremst.

Bei Bildverarbeitung z.B. wird ja mit jedem Takt ein Datum eingeworfen 
und soll hinten aus der Schlange rausfallen. Wenn irgendwo in der Kette 
eine Verzeigung und später eine Konjuktion auftritt, müssen die Pfade 
gleich langs sein. Da führt kein Weg dran vorbei.

Kurze Verzögerungen realisiert man daher mit FFs - lange mit RAMs, so 
verfügbar.

Nimm mal z.B. die Situation, dass der Betrag eines Vektors mit seinem 
Grundwert verrechnet werden soll, dann hast Du f(x,y) = g(x,y) o Wurzel 
(x*x,y*y). Die Wurzel dauert aber eine Weile in VHDL und es müssen 
später die dazugehörigen x,y verrechnet werden und nicht etwa die 
aktuellen. Bei einer VHDL-Wurzel mit hoher Auflösung gehen da schon mal 
30 Takte dahin. In dem Fall kann man es auch nicht automatisch machen 
lassen, weil die Verzögerung nicht konstant ist. Selbst beim 
System-Generator, der die Verzögerung ja kennt, musste man das noch per 
Hand einstellen. (!!!)

In anderen Fällen ohne Core ginge auch die rabiate Methode, nämlich 
alles in Variablen oder als Kombinatorik zu formulieren und dann ein 
FF-Grab hinten dran zu hängen, die der Synthesizer dann bitte passend 
hinbalanciert. Das geht aber nur für kurze Pfade, wie ich feststellen 
musste, weil sich die Synthese da gerne mal verrennt! Ich habe sogar 
Fälle, wo das vorsorgliche Hinzufügen von FFs zu schlechteren Ergebnisse 
führt, weil es nicht gebacken bekommt.

von J. S. (engineer) Benutzerseite


Lesenswert?

Duke Scarring schrieb:

> Wenn ein Modul auf mehrere Werte warten muss, werden die mit ihrem
> enable gelatcht und wenn alle da sind, geht es los.
Das heisst aber doch auch wieder, daß das Modul entweder warten muss, 
oder die pipe so getrimmt ist, dass es immer stimmt!

Und: Die Problematik tritt ja nicht nur über Module hinweg auf, sondern 
auch innerhalb jedes VHDL-Moduls. Die Rechenlängen müssen stimmen - 
siehe das Wurzelbeispiel hier drüber.

> Ob die Latenzen passen, sehe ich in der Testbench.
D.h. es kommt eben doch wieder auf händisches Beobachten an, ob die 
richtigen enables zusammenarbeiten. Wenn es eine kontinuierliche pipe 
ist, hätte man zudem ein Dauer-enable.

Mir fällt aber gerade eine Methode ein, wie man es automatisieren 
könnte, damit die Synthese immer die richtigen Werte verrechnet. Es 
würde sogar zur Laufzeit funktionieren, wenn sich die Rechnung verändert 
und eine andere Latenz bräuchte:

Man erzeugt zum Startzeitpunkt für jeden Datenpfad einen Zähler in einem 
solchen record, der mit hochgezählt wird. Verarbeitet werden nur Daten 
mit gleichem Zählerstand. Nun hat man zwei Möglichkeiten:

1) Man formuliert die Bedingung in die Rechnung mit rein, was dazu 
führt, dass die Rechnung ausfällt, solange man einen Fehler hat. Das 
Design arbeitet also wenn, dann richtig oder garnicht.

2) Man führt die Pfade auf FIFO-RAMs und verwendet die Zähler als 
Schreib-Adressen. Damit steuern sich die Delays selber und am Ausgang 
kommen immer die richtigen zu einander passenden Daten an. Das würde 
auch zur Laufzeit stimmen. Wenn man die Laufzeitumschaltung nicht 
benötigt, ermittelt man im ModelSIM aus der Differenz zwischen Lese und 
Schreibadresse das sich ergebende Delay und trägt es als statischen 
Vorlauf für jedes RAM ein. Dann werden die Zähler wegsynthetisiert.

von Schlumpf (Gast)


Lesenswert?

Ok, ich habe da eine "Ebene" abstrakter gedacht.

Ich ging davon aus, dass die Daten langsamer kommen (nicht zu jedem 
Takt) und die Berechnungsfunktion eben für n Takte beschäftigt ist, bis 
sie überhaupt wieder ein neues Datum annehmen kann. Dann wäre das mit 
dem Valid-Signal eine Lösung.

So wie ich es jetzt aber verstanden habe, dauert eine Berechnung n 
Takte, aber mit jedem Takt wird schon ein neues Datum in die Berechnung 
nachgeschoben und hinten purzeln mit n Takten verzögerung, aber mit 
JEDEM Takt ein neues Ergebnis raus.
Dann ist das mit dem Valid-Signal natürlich nicht anwendbar.

von Tom W. (Gast)


Lesenswert?

Jürgen S. schrieb:
> Mir fällt aber gerade eine Methode ein, wie man es automatisieren
> könnte, damit die Synthese immer die richtigen Werte verrechnet. Es
> würde sogar zur Laufzeit funktionieren, wenn sich die Rechnung verändert
> und eine andere Latenz bräuchte:

Welchen Anwendungsfall siehst Du da und wozu muss der 
Synthesemechanismus das zur "Compilezeit" (wenn man das so nennen kann) 
"wissen"?

Es würde doch einfach eine Verzögerungskette aus Delay-Gliedern reichen, 
die man zur Not umschalten kann! Bei uns entwickeln sie das mit 
MATLAB-Simulink und der hat ein solches Delay drin. Es ist rein virtuell 
und wird vom Synthesizer ausgefüllt.

von K. L. (Gast)


Lesenswert?

Thomas R. schrieb:
> Eine einfache Lösung gibt es nicht. Der FIFO Ansatz kann viele
> Ressourcen verbrauchen, denn jedes Modul muss soviel Stufen
> bereithalten, wie dass mit der größten Latenz zu dem es parallel
> geschaltet werden kann.

Hallo Thomas, das sieht sich sehr interessant aus, komme aber irgendwie 
auch nicht auf den Punkt, wo in der Arbeit dargelegt wird, wie sich das 
automatisieren liesse.

Ich denke, man müsste VHDL irgendwie dazu befähigen, eine Art von 
Zeitpunkten einzuführen, auf die sich der Entwickler bei der 
Formulierung des Zugriffs beziehen kann. Der Synthesizer müsste dann in 
der Lage sein, ausreichend viele Takte einzusetzen, wenn nötig.

Keine Ahnung, ob es sowas gibt.

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Wer mag: Hier ist ein Ansatz für die Lösung des Problems in Python:

http://opencores.org/project,lateq

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.