Hi,
ich habe neulich ein Design simuliert (ISE/Isim 13.3) und bin dabei
draufgekommen, dass ein FF mit einem synchronen Input einen Takt "zu
früh" geschalten hat - und zwar zum "exakt" (?) gleichen Zeitpunkt, als
der Input sich geändert hat. Was laut Hardware ja nie passieren kann, da
ein D-FF per Definition ja am Schaltzeitpunkt des Taktes den Wert am
Ausgang annimmt, den sein Eingang zuvor hatte (mal angenommen Setup/Hold
stimmen).
Dann bin ich der Sache auf den Grund gegangen und konnte den Sachverhalt
auf folgendes Szenario reduzieren und komplett in der Testbench
nachstellen:
Der "inp" wird für einen Takt geschalten und wird in zwei getrennten FFs
abgetaktet. Das Ergebnis ist, dass ein FF einen Takt früher, das zweite
später schaltet. Simulationsplot siehe Anhang.
1
pclk<=notpclkafter5ns;
2
pclk2<=pclk;
3
4
testt:process
5
begin
6
waitfor995ns;
7
waituntilrising_edge(pclk);
8
inp<='1';
9
waituntilrising_edge(pclk);
10
inp<='0';
11
wait;
12
endprocess;
13
14
testp:process(pclk)
15
begin
16
if(rising_edge(pclk))then
17
if(inp='1')then
18
test<='1';
19
else
20
test<='0';
21
endif;
22
endif;
23
endprocess;
24
25
testp2:process(pclk2)
26
begin
27
if(rising_edge(pclk2))then
28
if(inp='1')then
29
test2<='1';
30
else
31
test2<='0';
32
endif;
33
endif;
34
endprocess;
Als allererstes dachte ich an einen Codefehler. Danach an einen
ISIM-Bug. Dann hab ich ein bisschen recherchiert und bin auf das Thema
delta-Zyklen gestoßen. Anscheinend sollte man in der Simulation nicht
beliebig von einem Signal aufs andere zuweisen, wenn man wirklich
"gleichzeitige" Events haben will, da sonst die einzelnen Zeilen in
delta-Zyklen abgearbeitet werden und deshalb in meinem einfach Beispiel
der eine Takt früher wie der andere schaltet.
Siehe zb:
http://www.sigasi.com/content/vhdls-crown-jewel
und
Beitrag "Abgeleitete clocks in der Simulation - wie Probleme vermeiden?"
Nur, so ganz versteh ich's immer noch nicht. Kann mir das jemand
vielleicht kurz und prägnant erklären?
Dem Synthese-Tool ist sowas egal, in Hardware wird das einfach ein
Signal, egal wie oft man das hin und her zuweist oder nicht. Warum kann
das in der Simulation nicht auch auf ein Signal reduziert werden?
Und: irgendwie muss ich meine Clock ja im Design verteilen? Woher weiß
ich, welches port-map und welche Signalzuweisung nun ein Problem durch
einen oder mehrere delta-Zyklen darstellt und was nicht? Gibts hierfür
eine Faustregel?
Danke, lg Harry
PS: Gibts in ISim eine Möglichkeit, diese delta-Zyklen anzeigen zu
lassen? Ich glaube, Modelsim kann das.
Versuch erstmal, das Problem mit der "Gleichzeitigkeit" zu
verstehen:
...
wait until rising_edge(pclk); -- Abfrage Zeitpunkt T
inp <= '1'; -- Zuweisung Zeitpunkt T+Delta
...
d.h. <inp> wird erst "kurz nach" T beschrieben, zum Zeitpunkt
T hat <inp> noch seinen alten Wert. Und das hat Auswirkung auf
den nachfolgenden Code:
...
if(rising_edge(pclk)) then -- Abfrage Zeitpunkt T
if(inp = '1') then -- Abfrage Zeitpunkt T (alter Wert!)
test <= '1';
else
...
d.h. <inp> hat in T noch den alten Wert, erst in T+T_CLK kann der
neue Wert in diesem Prozess abgefragt werden. Soviel zum ersten Teil.
...
pclk2 <= pclk; -- Zuweisung Zeitpunkt T+Delta
...
if(rising_edge(pclk2)) then -- Abfrage Zeitpunkt T+Delta
if(inp = '1') then -- Abfrage Zeitpunkt T+Delta (neuer
Wert!)
test2 <= '1';
...
Hier wird <pclk2> und <inp> zum "gleichen" Zeitpunkt ein neuer Wert
zugeordnet, also klappt die Abfrage und Zuordnung wie gewünscht.
(genaugenommen müsste man Delta in Delta1 und Delta2 aufspalten,
von denen aber nicht bekannt ist, welche Differenz grösser ist)
Man kann sich das ganze auch als gerichteten Graphen vorstellen.
Der grosse Fehler ist also, dass du mit einer Clock schreibst und
mit einer anderen liest.
Ja wenn du einen Takt anfasst, musst du danach immer auf der Hut sein.
Innerhalb von Designs sollte man den Takt möglichst von weit oben in der
Hierarchie zuführen. In testbenches kann man noch eine konstante anfügen
zur Verzögerung
Klakx schrieb:> In testbenches kann man noch eine konstante anfügen> zur Verzögerung
Das hilft aber nur bei eingehenden Signalen, alle "internen"
Register-Signale werden idR mit rising_edge(clk) geschaltet,
d.h. der Phasenoffset ist wieder weg, es sei denn man passt
all seine Komponenten/Zuweisungen an (z.B. mit .. after 0.1 ns
etc.). Man kommt also um ein grundlegendes Verständnis nicht
rum.
Solche Unschönheiten gibt es auch bei ModelSIM, insbesonders, wenn man
den after-Konstrukt einsetzt.
In dem oben beschriebenen Fall ist das Problem aber kein
simulationstechnisches sondern da fallen ja in der simulierten Realität
Takte und Daten auf denselben infinitisimalen Zeitpunkt. Von daher ist
der Ergebnis "zufällig" bzw hängt von sequentiellen Ablauf ab. Das
sollte man dort, wo man das nicht benötigt, vermeiden, weil es den
Nutzen einer Logiksimulation mindert und diese erschwert.
Die Problematik ist bei korrekt formulierten Logikschaltungen nicht
gegeben, sondern tritt nur bei physikalischen Simulationen auf. Und
dabei muss man eben an jeder Stelle Zeiten einfügen und dabei
berücksichtigen, wenn man logische Zuweisungen macht, die hinter
verschwinden. Durch die tatsächliche Zeitdehnung in einer Simulation
gibt es eben keine echte Gleichzeitigkeit. Da hilft es dann tatsächlich,
mehr, wie in C zu denken und den Ablauf der Zeit straght forward runter
zu schreiben.
Jürgen Schuhmacher schrieb:> Solche Unschönheiten gibt es auch bei ModelSIM, insbesonders, wenn man> den after-Konstrukt einsetzt.
Keine Unschönheit, sondern Semantik der Simulation: Vor Simulationsstart
wird zuerst ein Graph (vgl.bar Petrinetz) erstellt und dann
abgearbeitet.
Die meisten Simulatoren arbeiten so.
> In dem oben beschriebenen Fall ist das Problem aber kein> simulationstechnisches sondern da fallen ja in der simulierten Realität> Takte und Daten auf denselben infinitisimalen Zeitpunkt.
Nein, es ist nicht derselbe infinitesimaler Zeitpunkt, es sind mind.
2 Zeitpunkte, einmal T und einmal T+.
>Von daher ist> der Ergebnis "zufällig" bzw hängt von sequentiellen Ablauf ab. Das> sollte man dort, wo man das nicht benötigt, vermeiden, weil es den> Nutzen einer Logiksimulation mindert und diese erschwert.
Zufällig ist das Ergebnis nicht, denn bei der Erstellung des Graphen
ist die Reihenfolge für das Simulationsergebnis irrelevant (es sei denn,
der Simulator hat disbezgl. einen Fehler).
Hallo an alle und danke für die ausführlichen Antworten.
Sigi schrieb:> Der grosse Fehler ist also, dass du mit einer Clock schreibst und> mit einer anderen liest.
Ja, anscheinend hab ich hier zuviel in Hardware und zu wenig in Software
gedacht. Denn für die Synthese wären pclk und pclk2 dasselbe und würde
auf ein Signal reduziert. Nicht so für den Simulator, was mir durch eure
Ausführungen nun etwas klarer ist.
Und das ist in der Realität dann schon eine gemeine Falle, denn das
angeführte Beispiel war ja gekünstelt, um den Effekt hervorzuheben. In
einer richtigen Testbench ist das ja typischerweise irgendwo
verschachtelt und man sucht ewig nach dem "Fehler", der nur in der
Simulation einer ist...
Eine Frage nochmal aufgeriffen:
> PS: Gibts in ISim eine Möglichkeit, diese delta-Zyklen anzeigen> zu lassen? Ich glaube, Modelsim kann das.
Danke, lg
Harry schrieb:> Und das ist in der Realität dann schon eine gemeine Falle, denn das> angeführte Beispiel war ja gekünstelt, um den Effekt hervorzuheben. In> einer richtigen Testbench ist das ja typischerweise irgendwo> verschachtelt und man sucht ewig nach dem "Fehler", der nur in der> Simulation einer ist...
..nicht die einzige Falle: Nimm z.B. ein std_logic_vector und teile ihn
in zwei Teile. Je ein Teil wird von einem Prozess geschrieben, beide
Teile aber von beiden Prozessen gelesen. Dann gibt's auch Probleme.
Das liegt daran, dass der (jeder!) Simulator einen gerade beschriebenen
Vektor markiert, nicht aber Teile davon. Den Rest kann man sich dann
selbst zusammenreihmen.
Dies ist kein Simulator-Fehler, sondern in VHDL spezifiziert.
Kleine Denksportaufgabe: wie sieht's mit Komponenten-Ports aus, dabei
werden ja Signale an verschiedene Komponenten weitergereicht?
> Eine Frage nochmal aufgeriffen:>> PS: Gibts in ISim eine Möglichkeit, diese delta-Zyklen anzeigen>> zu lassen? Ich glaube, Modelsim kann das.
Wahrscheinlich nicht, Delta-Zyklen sind ja nur ein abstraktes Konstrukt,
um "Jetzt" von "Gleich" zu unterscheiden, was durch Graphen bzw.
Markierungen implementiert wird.
Interesant wäre eher, zu welchen Zeitpunkt welche Signale schon
beschrieben und welche "gleich" beschrieben werden.
Sigi schrieb:> Nimm z.B. ein std_logic_vector und teile ihn> in zwei Teile. Je ein Teil wird von einem Prozess geschrieben, beide> Teile aber von beiden Prozessen gelesen.
Wer so einen Scheiss programmiert, dem gehört es auch nicht besser,
Probleme zu bekommen!
> Kleine Denksportaufgabe: wie sieht's mit Komponenten-Ports aus, dabei> werden ja Signale an verschiedene Komponenten weitergereicht?
Wird je nach Optimierungseinstellung des Compilers plattgerechnet.
> Wahrscheinlich nicht, Delta-Zyklen sind ja nur ein abstraktes Konstrukt,
Und gehen in der compilierten Simulation komplett unter.
Ich kann nur davor warnen, sich unnötig von solchen Geschichten abhängig
zu machen. Ich empfehle dazu das Buch: "ASIC and FPGA Verification" von
Richard Munden.
Weltbester FPGA Pongo schrieb im Beitrag #4082503:
>> Kleine Denksportaufgabe: wie sieht's mit Komponenten-Ports aus, dabei>> werden ja Signale an verschiedene Komponenten weitergereicht?>> Wird je nach Optimierungseinstellung des Compilers plattgerechnet.
Abgesehen davon, dass ich bei keinem Simulator je irgendwelche Compiler
Optimierungen gesehen habe, stimmt das sicher nicht, da man dann je nach
Einstellung unterschiedliche Simulationsergebnisse hätte.
Port Zuweisungen werden durchgereicht, und zeigen auf das selbe Signal.
Sie erzeugen keinen Delta-Zyklus.
Sie sind nicht das selbe wie eine concurrent Zuweisung außerhalb eines
Prozesses.
Dass eine concurrent Zuweisung einen Delta-Zyklus erzeugt, hängt damit
zusammen, dass sie GENAU wie ein Prozess wirken und im Simulator auch so
behandelt werden.
1
a<=b;-- a,b sind Signale
ist genau das selbe wie
1
process(b)
2
begin
3
a<=b;
4
endprocess;
Erst wenn b zum Zeitpunkt T sich ändert, beginnt der Prozess zu laufen.
An a wird zugewiesen, a ändert sich aber erst am Ende des Zeitschrittes,
wenn alle Prozesse wieder gestoppt wurden.
Somit erhält a erst zwischen T und T+DeltaZyklus den neuen Wert b und
triggert somit womöglich zum Zeitpunkt T+Deltazyklus wiederum neue
Prozesse.
Klaus Falser schrieb:> Weltbester FPGA Pongo schrieb im Beitrag #4082503:> ..>> Wird je nach Optimierungseinstellung des Compilers plattgerechnet.>> Abgesehen davon, dass ich bei keinem Simulator je irgendwelche Compiler> Optimierungen gesehen habe, stimmt das sicher nicht, da man dann je nach> Einstellung unterschiedliche Simulationsergebnisse hätte.
Genau. Das wäre eine totale Katastrophe.
>> Port Zuweisungen werden durchgereicht, und zeigen auf das selbe Signal.> Sie erzeugen keinen Delta-Zyklus.> Sie sind nicht das selbe wie eine concurrent Zuweisung außerhalb eines> Prozesses.
Sehr gut, dasselbe gilt für Aliases.
Weltbester FPGA Pongo schrieb im Beitrag #4082503:
>> Wahrscheinlich nicht, Delta-Zyklen sind ja nur ein abstraktes Konstrukt,>> Und gehen in der compilierten Simulation komplett unter.
Eben nicht, alle Simulatoren wandeln vor Siumlationsstart das HDL-Design
in einen Graphen/Netzwerk um, die Sematik bzgl. Delta-Zyklen wird dabei
erhalten.
> Ich kann nur davor warnen, sich unnötig von solchen Geschichten abhängig> zu machen. Ich empfehle dazu das Buch: "ASIC and FPGA Verification" von> Richard Munden.
Die einzige Möglichkeiten sich vor dem Delta-Zyklen-Ansatz zu schützen
ist nicht zu simulieren (oder Post-Sims zu benutzen => langsam). Aber
das ist noch schlechter.