Hallo in die Runde,
ich möchte gerne ein X in der Simulation unterdrücken und den selben
Code zur Synthese verwenden. Dazu schreibe ich mir ein Modul, welches
folgende Funktionalität abbildet:
1
-- Simulation:
2
ifis_x(DataIn)then
3
DataOut<=(others=>'0');
4
else
5
DataOut<=DataIn;
6
endif;
7
8
-- Synthese:
9
DataOut<=DataIn;
Kann ich das Simulationskonstrukt auch in der Synthese verwenden, ohne
dass zusätzliche Logik generiert wird? Ein X gibt es ja in der Hardware
nicht.
Alternativ wäre ein If Generate vielleicht eine Option. Wie kann ich für
die generate Condition erkennen, ob es sich um eine Simulation oder eine
Synthese handelt?
Leider gibt es keine so richtig gut portable Loesung, aber fuer deinen
Fall ist wohl das `if .. generate` Konstrukt ausreichend, das Setzen der
entsprechenden Konfig-Variable wiederum toolabhaengig. Sonst weitere
Optionen, die allerdings auch trotz Standardisierungsbemuehungen nicht
bei allen Tools gleich funktionieren:
* VHDL configurations
* Pragmas ('-- pragma synthesis_off/on', etc.)
Die generate-Variante duerfte die portabelste sein, solange man keine
Scherze wie konditionale Einbindung von Modulen bei der
Lattice-Toolchain ausprobiert.
Fpga I. schrieb:> Kann ich das Simulationskonstrukt auch in der Synthese verwenden, ohne> dass zusätzliche Logik generiert wird?
Ich würde das einfach mal selber ausprobieren und mir den RTL-Plan und
den Ressourcenbedarf ansehen und vergleichen.
Aber ich würde glatt mein Auto drauf wetten, dass der Synthesizer keine
Hardware dafür erzeugt.
> Ein X gibt es ja in der Hardware nicht.
Ein X gibt es "in der Hardware" schon: das ist eine übliche
Buskollision, wenn wzei Teilnehmer gleichzeitig schreibend auf einen Bus
zugreifen und der eine ein low, der andere aber ein high treibt.
Aber wenn die "Hardware" ein FPGA ist, dann gibt es da innen drin nur
'0' und '1'. Heutige FPGAs haben nicht mal mehr ein 'Z'.
Lothar M. schrieb:> Aber ich würde glatt mein Auto drauf wetten, dass der Synthesizer keine> Hardware dafür erzeugt.
Da gehe ich mit ;-)
Aber die Frage ist, ob die Synthese das 'X' dann als '0' oder '1'
ansieht bzw. der Test auf 'X' true oder false ist.
Ich vermute mal letzteres - also false. Aber da es nicht im
VHDL-Sprachstandard definiert ist, kann jeder Hersteller das handhaben
wie er will.
> Aber die Frage ist, ob die Synthese das 'X' dann als '0' oder '1'> ansieht bzw. der Test auf 'X' true oder false ist.>> Ich vermute mal letzteres - also false.
Eher nicht.
Also angenommen ein Treiber trübe Vcc, ein anderer trübe GND - dann ist
das Ergebnis Vcc/2, was mit ziemlicher Sicherheit im
verbotenen/undefinierten Bereich des Signalstandards gehört.
Mal zum Vergleich der TTL-Standard:
https://de.wikipedia.org/wiki/Logikpegel
Man könnte hier auch einen Exkurs in Richtung Metastabilität folgen
lassen.
https://de.wikipedia.org/wiki/Metastabilit%C3%A4t_(digitale_Schaltung)
Hä?
Wir sind hier bei der Synthese (und Simulation), nicht beim Betrieb
eines FPGAs und schon gar nicht bei Metastabilität und gegeneinander
arbeitende Treiber (im FPGA)!
Meine Vermutung, dass die Synthese den Vergleich auf 'X' als false
ansieht, beruht einfach darauf, dass 'X' immer ungleich '0' und ungleich
'1' ist ;-)
Also nach allgemeinen Verständnis ist gerade die Synthese der Übergang
von idealisierten zweiwertigen "Richtig"/"Falsch" Denken in die reale
Welt von (analogen/Kontinuirlichen) Spannungen.
> Meine Vermutung, dass die Synthese den Vergleich auf 'X' als false> ansieht, beruht einfach darauf
Ich vermute, die Synthese bricht mit Fehlermeldung ab, sobald sie auf
einen solchen Vergleich im Quelltext trifft.
Halbwegs sinnvoll, wenn auch nicht immer korrekt, wäre noch eine
Interpretation als "don't care". Siehe Anhang (aus:
http://www.gstitt.ece.ufl.edu/courses/spring10/eel4712/lectures/vhdl/xst.pdf)
Für Vivado:
https://support.xilinx.com/s/article/64042?language=en_US
-> für vivado synthese vermeide 'X' und 'U' in Vergleichen
Bradward B. schrieb:> Ich vermute, die Synthese bricht mit Fehlermeldung ab, sobald sie auf> einen solchen Vergleich im Quelltext trifft.
Nein, tut sie nicht - gerade mit Synplify getestet. Warum sollte sie
auch? 'X' ist immer ungleich '0' oder '1'.
Außerdem ist es zulässig, Konstanten (std_logic) mit 'X', 'Z', 'H', 'L'
usw. zu definieren und im weiteren Quelltext diese zu vergleichen (und
entsprechende unterschiedliche Aktionen zu bewirken). Und warum sollte
das nicht auch bei Signalen möglich sein?
Einzig der Verleich von Was-auch-immer auf '-' (don't care) könnte die
Synthese sinnvoll als true betrachten.
> Einzig der Verleich von Was-auch-immer auf '-' (don't care) könnte die> Synthese sinnvoll als true betrachten.
Dont care ist mit 'X' und mit '-' assoziiert(siehe Anhang oben). Und
Dont'care ist weder explizit "true" oder "false". Wobei true and false
doch eher vom type boolean ist, während 'X' zur neunwertige Logic
std_logic aka IEEE-1164 gehört.
> Nein, tut sie nicht - gerade mit Synplify getestet
Synplify nist eines von vielen Synthesetools, da gibt es keinen
herstellerübergreifenden Standard. Schon bei unterschiedlichen
synthesetargets/Architekturen kann man unterschiedliche Ergebnisse
erreichen.
Bradward B. schrieb:> Dont care ist aber mit 'X' definiert
Das macht Xilix ganz willkürlich bei XST so.
Ob das Vivado oder Synplify auch so handhaben, steht auf einem ganz
anderen (Daten-) Blatt.
> Und Dont'care ist weder explizit "true" oder "false"
Habe ich weder geschrieben noch behauptet.
Pat A. schrieb:> Bradward B. schrieb:>> Dont care ist aber mit 'X' definiert>> Das macht Xilix ganz willkürlich bei XST so.> Ob das Vivado oder Synplify auch so handhaben, steht auf einem ganz> anderen (Daten-) Blatt.
Auf das "Blatt" von Vivado wurde bereits verwiesen, bei Vivado wird
empfohlen auf 'X' bei Comperatoren zu verzichten um eben die
Mehrdeutigkeiten von don't care zu vermeiden.
>> Und Dont'care ist weder explizit "true" oder "false">> Habe ich weder geschrieben noch behauptet.
Naja, da wird ziemlich oft Dont'care in einem Atemzug mit "true" und
"false" genannt, obwohl "true" und "false" in VHDL zum enum typ boolean
gehören und "X" und "-" dagegen zum enum type std_logic. Und std_logic
gehört genau genommen nicht zum selben standard wie VHDL mit boolean
(IEEE-1076) sondern wurzelt in einem eigenen (IEEE-1164).
Bradward B. schrieb:> Naja, da wird ziemlich oft Dont'care in einem Atemzug mit "true" und> "false" genannt
Sind meine Sätze zu lang bzw. zu kompliziert für Dich?
Ok, dann mal als Essenz: "Ein Test/Vergleich von ... ergibt true bzw.
false."
Und sei Dir sicher, 'boolean' und 'std_logic' kann ich gerade so schon
unterscheiden, obwohl ich VHDL erst seit gestern mache ;-)
So, das wars für mich hier, ich bin dann mal raus. Die Lösung für den TO
steht schon im 2. und 3. Beitrag.
Noch ein schönes Wochenende!
> So, das wars für mich hier, ich bin dann mal raus. Die Lösung für den TO> steht schon im 2. und 3. Beitrag.
Der 3. Beitrag enthält (Hersteller-) proprietäre Schlüsselworte und ist
somit als allgemeine Lösung untauglich.
https://insights.sigasi.com/tech/list-known-vhdl-metacomment-pragmas/
Und der zweite Beitrag wiederholt im wesentlich den "workaround" den der
TO selbst vorgeschlagen hat und verweist im weiteren darauf, das es
keine allgemeine Lösung gibt.
Mal unabhängig von irgendwelchen Standards und wie sie von den
Toolherstellern interpretiert werden: Das Codebeispiel des TO hat in der
Simulation ein anderes Verhalten als in der realen Hardware. Das ist
schon mal ganz schlechter Style. Ein undefinierter Signalszustand darf
in einem korrekten Design keinen Einfluss auf das Ergebnis haben, weil
das sonst indeterministisch wird. Insbesondere kann ein solcher
X-Zustand nicht verwendet werden, um damit einen Multiplexer zu steuern,
weil eine digitales Design einfach nicht in der Lage ist, ein X als
solches zu erkennen.
Es ist daher sinnvoll, is_x() währnd der Synthese grundsätzlich als
false anzunehmen und wegzuoptimieren, und der Großteil der Tool macht
das auch so (und gibt zumindest eine Warnung aus).
Aber die saubere Lösung ist, eindeutig zwischen Synthese- und
Simulationskontext zu unterscheiden, sprich die schon vorgeschlagene
Lösung mit einem GENERATE-Konstrukt (bzw. ifdef in Verilog). Da die
Syntesetools dann das is_x() gar nicht zu sehen bekommen, ist die
Bedeutung des Codes eindeutig- sowohl für die Tools als auch denjenigen,
der den Code lesen und verstehen muss.
Es gilt auch hier: Eindeutigkeit zum Preis von ein paar mehr Lines of
Code ist mehr Wert als freakige Shortcuts mit situationsabhängiger
Semantik. Das steht in der Einleitung von so ziemlich jedem brauchbaren
Styleguide.
Dank Euch für Euren Antworten.
Noch ein kleiner Hintergrund, wie das X zustande kommt:
Es wird immer nur ein Teil eines Blockrams geschrieben und anschließend
der volle Inhalt de Blockrams versendet (incl. CRC Berechnung über BRAM
Inhalt). Protokolltechnisch erkennt der Empfänger, wo das Ende der
genutzten Bytes innerhalb der Nachricht ist, sodass der hintere Teil ein
"Don't Care" ist. Lediglich die CRC wird über die volle Nachricht
berechnet. Ist das Blockram nicht initialisiert, liest die Simulation
ein X zurück, während das FPGA dort typischer Weise eine '0' stehen hat
(genaueres findet sich im Datenblatt der zugehörigen Bausteinfamilie).
Aufgrund der Verwendung generischer vorhandener Module kann das Blockram
nicht initialisiert werden (in anderen Kontexten möchte ich das X gerne
sehen, um in der Simulation gleich darüber zu stolpern, wenn ich zu viel
aus dem RAM lese).
Damit ich eine CRC sowohl sendeseitig als auch empfangsseitig berechnen
kann, darf in der Simulation also kein X aus dem Blockram kommen.
Ich habe nun die passenden Lösungsansätze an der Hand und werde noch mal
kurz in mich gehen und dann eine Variante auswählen. D
Fpga I. schrieb:> Dank Euch für Euren Antworten.>> Noch ein kleiner Hintergrund, wie das X zustande kommt:> Protokolltechnisch erkennt der Empfänger, wo das Ende der> genutzten Bytes innerhalb der Nachricht ist, sodass der hintere Teil ein> "Don't Care" ist. Lediglich die CRC wird über die volle Nachricht> berechnet. Ist das Blockram nicht initialisiert, liest die Simulation> ein X zurück, während das FPGA dort typischer Weise eine '0' stehen hat> (genaueres findet sich im Datenblatt der zugehörigen Bausteinfamilie).
Also in Echt würde dort eine '0' stehen aber wegen "suboptimal"
aufgesetzter Simulation bringt das Model ein 'X' (BTW, ein X steht nicht
für "don't care" sondern für "Unknown" und bei Unitialisiert wäre
eigentlich ein 'U' gefordert https://en.wikipedia.org/wiki/IEEE_1164 )
???
IMHO ist das die Ursache des Problems an dem man sinnvollerweise eine
Lösung ansetzen sollte.
Und AFAIK gibt es für jeden BlockRAM eine Möglichkeit der
Initialisierung, da man diesen BRAM auch als ROM einsetzen könnte. Also
einfach ein korrektes Model des BRAM benutzen/anfordern, möglicherweise
liegt es nur an einem suboptimal gesetzten Haken bei der
Source-Generierung.
Anbei ein Auszug diesbezüglich für die Xilinx series-7 Familie. Wenn
genannt würde, welche Familie konkret eingesetzt wird, könnte man das
natürlih auch raussuchen.
Ich beschreibe mein RAM in VHDL. Die Initialisierung des BRam wäre
technisch problemlos möglich, ist aber nicht gewünscht:
Ich ein generisches Memory Modul, welches mir u.a. ein double buffering
implementiert. Da das Modul auch in anderen Projekten zum Einsatz kommt,
möchte ich das BRam nicht initialisieren, da es normalerweise ja ein
Fehler ist, wenn ich Daten lese, die zuvor nicht geschrieben wurden. In
sofern hat das X in der Simulation schon seine Berechtigung und soll
gerne sichtbar bleiben.
Das aktuelle Projekt bildet ist eine Ausnahme, dort ist es ok, Werte zu
lesen und weiter zu verarbeiten, die nie geschrieben wurden.
Ich habe mir übrigens mit einem Modul beholfen, welches ich hinter die
BRam ReadData hänge. Es enthält eine einzige Concurrent Anweisung:
o_DataOut <= to_01(i_DataIn);
P.S.: Ob in der Simulation dort ein X oder U stand, weiß ich nicht mehr,
vermutlich ein U, aber beides wird ja durch die Funktion is_x()
abgefangen
Fpga I. schrieb:> Da das Modul auch in anderen Projekten zum Einsatz kommt,> möchte ich das BRam nicht initialisieren, da es normalerweise ja ein> Fehler ist, wenn ich Daten lese, die zuvor nicht geschrieben wurden. In> sofern hat das X in der Simulation schon seine Berechtigung und soll> gerne sichtbar bleiben.
Für jedes "Fehler-szenario" sollte man ein eigenen Check im
Simulationsmodel haben. Hier habe ich den Eindruck, das drei
verschiedene Szenarien mit dem selben abgedeckt Test werden sollen:
* Speicherfeld ist nicht initialisiert
* Lesen einer Speicherstelle die nicht vorher beschrieben wurde
* mehrer Signalsender treiben gleichzeitig eine Signalleitung.
Das dritte wird IMHO durch ein 'X' angezeigt, ersteres 'U'. Natürlich
ist es bei der dritten variante wichtig, ob ein Typ mit resolution
function ('std_logic') oder ohne ('std_ulogic') benutzt.
https://tams.informatik.uni-hamburg.de/applets/hades/webdemos/00-intro/03-stdlogic/resolution.html
Das zweite -read without write- wird durch einen Test im Speicher-modell
selbst abgefangen, respektive bei der Simulation gabs eine
warning/report (VHDL-assert) im log.
Der ersten Fall (nicht-initialisierung) könnte/sollte wo nötig
(Parameter-file/ROM) zu einem Test auf richtige Init-Datensatz erweitert
sein. Das macht aber auch gerne die Software beim PowerUp-Test selbst,
sie prüft ob zu Softwareversion passende Parameter-daten vorhanden sind.
Bradward B. schrieb:> * mehrer Signalsender treiben gleichzeitig eine Signalleitung.>> Das dritte wird IMHO durch ein 'X' angezeigt, ersteres 'U'. Natürlich> ist es bei der dritten variante wichtig, ob ein Typ mit resolution> function ('std_logic') oder ohne ('std_ulogic') benutzt.
Ein 'X' kommt auch z.b. durch arithmetische Operationen von
uninitialisierten Werten zustande. Mal ganz abgesehen vom RAM-Modell,
welches auch in gewissen Szenarien ein 'X' aktiv schmeissen koennte.
Da die TDP-Modelle mit ihren unzaehligen Konfigurationsmoeglichkeiten
einiges an Kombinatorik bereithalten, kommt da schon mal ein 'U' als ein
'X' raus.
Dann kommen noch Unterschiede zwischen VHDL93 und VHDL08 dazu, die nicht
ueberall korrekt nach Standard abgefertigt werden. Da zeigte Xsim in der
Vergangenheit auch mal was anderes an als GHDL.
Bradward B. schrieb:> Und AFAIK gibt es für jeden BlockRAM eine Möglichkeit der> Initialisierung, da man diesen BRAM auch als ROM einsetzen könnte.
Meistens ja. Aber z. B. die RAM Blöcke im (betagten) ProASIC3 können das
nicht (Wir setzen den in der RT Variante aktuell noch immer ein).