Hallo liebe FPGA Gemeinde,
bitte nicht gleich steinigen, dass ich im Jahr 2020 noch ISE verwendet
habe :-) Ich bin ambitionierter Hobbyist und ISE funktionierte einfach
super für mich die ganze Zeit.
Nun bin ich durch äußere Umstände gezwungen auf Vivado zu wechseln und
verzweifle an einer "Kleinigkeit":
Wie konvertiere ich das hier richtig von UCF nach XDC:
1
## EAE's combinatorial division networks take longer than
2
## the regular clock period, so we specify a timing constraint
3
## for them (see also the comments in EAE.vhd)
4
INST "eae_inst/op*" TNM="EAE_OPS";
5
INST "eae_inst/res*" TNM="EAE_RES";
6
TIMESPEC TS_EAE=FROM "EAE_OPS" TO "EAE_RES" 32 ns;
Weitere Details dazu gibt es hier:
https://github.com/sy2002/QNICE-FPGA/blob/develop/hw/xilinx/MEGA65/ISE/MEGA65.ucf#L12
Ich habe schon relativ intensiv gegoogelt und habe nun die Hypothese,
dass ich irgendwie mit set_max_delay arbeiten muss?
Insbesondere in den forums.xilinx.com sind viele Beispiele und auch in
ug911-vivado-migration.pdf, aber ich verstehe nicht, wie ich diese
beiden "Punkte" in meinem kombinatorischen Netzwerk ("op*" und "res*")
so im XDC spezifizieren kann, dass Vivado sie in set_max_delay auch
findet.
Hier ist der zugehörige Quelltext:
https://github.com/sy2002/QNICE-FPGA/blob/develop/vhdl/EAE.vhd
Viele Grüße
Mirko
Danke für den Tipp! Also "set_multicycle_path" anstatt "set_max_delay"?
Aber wie spezifiziere ich die Endpunkte für "set_multicycle_path"? Wie
transformiere ich die ehmals sehr eleganten
Mirko H. schrieb:> Danke Dir, Tobias für die Rückmeldung. Der zugehörige VHDL Code> ist> hier:>> https://github.com/sy2002/QNICE-FPGA/blob/develop/vhdl/EAE.vhd
Ups, war wohl ein Feierabend Bier zuviel. :-(
Welche Periode hat den die Clock? Das ganze ist wahrscheinlich schon ein
Multicycle, nur dass nicht die Clock PEriode sondern fix 32 ns angegeben
sind.
In Vivado waere das sowas in etwa
DAs waere ein Beispiel fuer 2 Clockzyklen. In deinem Fall waeren das
dann die 32 ns geteilt durch die Clock Periode. Bei -hold traegst dann
eins weniger ein als bei -setup.
Bisschen Lesestoff dazu ist in UG903 zu finden, Kapitel Timing
Exceptions -> Multicycle Path. UG911 ist auch ganz interessant fuer
dich, da sind jede Menge Hilfestellungen zu finden um von IE nach Vivado
zu migirieren (fuer dein Fall ist auf Seite 25 ein Beispiel).
Kleiner Nachtrag: Ich habs jetzt nicht ausprobiert, evtl. sind noch
kleine Syntax Fehler drin. Aber vom Prinzip her muesste es korrekt sein.
;-)
Vorausgeschickt: mit X* kenn' ich mich nicht aus. Ob das folgende (das
in Quartus so funktioniert) auch bei Vivado so läuft, weiß ich nicht.
Jedenfalls ist ein .sdc-File bei Quartus einfach ein tcl Script.
Mirko H. schrieb:> Aber wie spezifiziere ich die Endpunkte für "set_multicycle_path"? Wie> transformiere ich die ehmals sehr eleganten> INST "eae_inst/op*" TNM="EAE_OPS";> INST "eae_inst/res*" TNM="EAE_RES";
um ehrlich zu sein: besonders "elegant" finde ich das nicht. Das ist
doch nichts anderes als eine Gruppenbildung?
1
set eae_ops [get_cells eae_inst/op*]
2
set eae_res [get_cells eae_inst/res*]
macht praktisch dasselbe: alle Elemente, auf die die Wildcards passen,
sind anschliessend unter den Namen $eae_ops bzw. $eae_res ansprechbar.
Dann - wie von Tobias B. schon geschrieben, diese Gruppen einfach in
set_multicycle_path verwenden:
Das erste Statement sagt, dass auf allen Pfaden von $eae_ops nach
$eae_res nicht mehr die Default-Regel gilt, dass das/die Signal(e) vor
der nächsten (1 = default) Latch-Taktflanke stabil am Ziel verfügbar
sein müssen, sondern dass die übernächste (2) auch noch reicht.
Das zweite Statement sagt, dass das/die Signal(e) statt frühestens
nach der (0. = default) an der (1). Latch-Taktflanke danach am Ziel
ankommen dürfen.
Ich finde das ehrlich gesagt viel eleganter und eingängiger als
1
TIMESPEC TS_EAE=FROM "EAE_OPS" TO "EAE_RES" 32 ns;
Noch dazu musst Du das Statement ändern, wenn Du den Takt änderst.
set_multicycle_path musst Du nur ändern, wenn Du das Design änderst.
Hallo Tobias und Markus,
herzlichen Dank für Eure Hilfe! Auch die Pointer zu der Doku, sowie die
Erklärung zu -setup und -hold waren hilfreich.
Ich konnte inzwischen Timing Closure erreichen. Für das Archiv, falls
mal jemand anders danach googelt - hier sind die finalen Constraints,
die bei mir geholfen haben:
(Jedes set_multicycle_path stellt eine Zeile dar; der Zeilen-Umbruch
wird hier von der Forumsoftware gemacht.)
Man sieht, dass Vivado im Gegensatz zu ISE deutlich spezfischer ist: Man
gibt noch mit _reg[*] die Endpunkte (in meinem Fall sind es Register)
an.
Ein wichtiger Punkt noch, es gibt keinerlei Konsistenzcheck zwischen
Multi-Cycle-Timing-Constraints und VHDL-Code. D.h. du musst selber
sicherstellen dass das Ergebnis erst nach drei Takten im Flipflops
gespeichert wird. Deutlich unsauberer ist die hier genutzte Variante
jeden Taktzyklus abzuspeichern und erst in der aufrufenden Einheit
sicherzustellen dass lange genug gewartet wird bevor das Ergebnis
gelesen wird.
@Blechbieger und @Tobias: Im Allgemeinen kann ich Euch da natürlich
nicht widersprechen.
In meinem speziellen Anwendungsfall aber ist die Grenze zwischen
"verhunzt" und "elegant oder zumindest zweckmäßig" fließend :-)
Das EAE (Extended Arithmetic Element) ist ein Coprozessor für die QNICE
CPU, der via Memory-Mapped IO (MMIO) angesprochen wird. Das dauert
relativ lange, da die CPU in so einem Fall 4-5 Zyklen für eine
Instruktion braucht.
Bis also nach dem Laden der Operanden auf das Ergebnis zugegriffen wird,
ist aufgrund der Systemarchitektur garantiert, dass genug Zyklen
vergangen sind und das Rechenergebnis sich gesettled hat.
Früher hatte ich eine VHDL Version, die ein BUSY Flag erzeugt hat,
während der Rechnerei. Dieses Flag hatte ich dann im Assembler Code
abgefragt (natürlich hätte man alternativ auch mit CPU Waitstates
arbeiten können):
https://github.com/sy2002/QNICE-FPGA/blob/master/monitor/math_library.asm#L61
Das war aber aufgrund der garantierten Timing-Gegebenheiten in dieser
speziellen Architektur Konstellation dann doch nicht mehr nötig...
Mirko H. schrieb:> In meinem speziellen Anwendungsfall aber ist die Grenze zwischen> "verhunzt" und "elegant oder zumindest zweckmäßig" fließend :-)
Was mich hier halt wundert ist, dass das ueberhaupt mit einem Multicycle
funktioniert. Ich habe gerade mal folgendes mit Vivado synthetisieren
lassen:
Tobias B. schrieb:> Benoetigt ganze 575 LUTs und ich bin etwas verwundert, dass das> innerhalb von 3 Taktzyklen laufen soll. Wird da evtl. ein riesen ROM> instanziert?
Sehr gute Frage!
Ich bin leider nicht firm genug sie zu beantworten.
Mir war auch aufgefallen, dass sowohl bei ISE als auch bei Vivado mit
dem Target Artix-7 (ich nutze einen XC7A100T) die Multiplikation mit dem
DSP implementiert wird und die Division mit eine großen Menge von LUTs.
Als reiner "self-taught" Hobby-VHDL-Entwickler fehlt mir etwas der
Hintergrund, ob das nun OK so ist, oder ob ich da nochmal 'ran sollte.
Sowohl mit ISE als auch nun (dank Euren Tipps und Hinweisen) mit Vivado
erreiche ich Timing Closure.
Und es funktioniert einwandfrei: Die Division wird bei der FAT32
Implementierung des QNICE ausgiebig verwendet und sie scheint seit dem
Jahr 2016, als ich das implementierte, 100% stabil zu funktionieren.
==> Von daher würde ich diesen Thread als "erfolgreich beantwortet"
betrachten wollen. Danke nochmal an alle für die Hilfe.
Falls aber jemand von Euch noch Tipps hat, wie ich das Ganze besser
machen könnte oder sollte und noch ein paar Pointer für mich zum
Lesen/Lernen hat - oder falls jemand Lust hat, das Ganze auf eine
wirklich neue (professionellere) Ebene zu heben und auf GitHub einen
Pull Request zu machen: Herzlich willkommen, würde mich freuen.
Tobias B. schrieb:> Benoetigt ganze 575 LUTs und ich bin etwas verwundert, dass das> innerhalb von 3 Taktzyklen laufen soll. Wird da evtl. ein riesen ROM> instanziert?
Quartus macht 576 (warum eigentlich?) LEs draus und der Timing Analyzer
ermittelt für das Kombinatorik-Monster eine Worst-Case Durchlaufzeit von
etwa 31 ns für einen Cyclone III (Speedgrade 6) im besten Fall.
Könnte also mit einem etwas moderneren Gerät gerade so hinkommen.
Ok, das ist stark. Das ist eine wirkliche Alternative zu nemm Divider
IP, sofern man kein Pipelining braucht. Definitiv etwas was ich mir im
Hinterkopf behalten. :-)