Hallo,
ich hab es mir angewöhnt Variablen in Prozesse zu verwenden, weil es zum
Einen übersichtlicher ist, wenn die Deklarationen direkt beim Prozess
stehen und zum Anderen, weil man aktuell zugewiesene Werte gleich wieder
lesen kann.
Ich hab mitgekriegt, dass immer davon abgeraten wird, dass man das macht
und man soll Signale stattdessen verwenden.
Ich programmiere VHDL seit 2 Jahren und auch deutlich mehr als nur
irgendwelche Blinklichter und hab z.B. FIR-Filterbänke mit Variablen usw
implementiert und nie Probleme festgestellt.
Woher kommt es, dass jeder so gegen Variablen ist? Ich finde es
übersichtlicher, einfacher zu verwenden und es ist klarer, was passiert.
Weiß jemand was dazu?
Grüße
thomas
@thomas (Gast)
>Woher kommt es, dass jeder so gegen Variablen ist? Ich finde es>übersichtlicher, einfacher zu verwenden und es ist klarer, was passiert.
Weil Variablen ein anderes Zuweisungsverhalten als Signale haben, und
das von Anfängern gern missverstanden wird. Hatte ich vor einiger Zeit
schon mal am Beispiel dargestellt, musst du mal suchen.
MFG
Falk
Ich bevorzuge die uniforme Verwendung von Signalen zur Synthese,
weil sonst solche Ammenmärchen auftauchen:
http://esd.cs.ucr.edu/labs/tutorial/
unter "Discussion I: Signal vs. Variable".
Da wird z.B. behauptet, die Ergebnisse der beiden Prozesse
(http://esd.cs.ucr.edu/labs/tutorial/sig_var.vhd) seien anders, weil das
in der Simulation so aussieht
(http://esd.cs.ucr.edu/labs/tutorial/sig_var.jpg). Der Fehler liegt hier
aber nicht im unterschiedlichen Verhalten von Signalen und Variablen,
sondern schlicht und einfach in der unvollständigen Sens-List vom proc2.
Und das passiert leicht, wenn man einen Prozess erst mal mit Variablen
beschreibt, und dann dieses prozessinterne Ergebnis global haben möchte.
Beim anschliessenden manuellen Ersetzen der Variable durch ein Signal
wird schon mal die Sens-List vergessen.
In der Hardware werden beide Prozesse (abgesehen von einer Warnung wegen
der unvollständigen Sens-List) sowieso identisch realisiert (Bild).
Korrekt müsste die Sens-List vom proc2 so heissen:
1
proc2:process(d1,d2,d3,sig_s1)
Dann stimmt auch das Verhalten der beiden Prozesse überein.
In der Simulation, wo ich ja mal den gesamten Syntaxumfang von VHDL
ausschöpfen darf, sind mir Variablen gern gesehen.
Auch zur Beschreibung und Bearbeitung von Schleifen in der Synthese sind
sie (oft) unumgänglich.
Aber für Anfänger (und auch für mich, obwohl kein Anfänger mehr) gilt:
Versuche, die Aufgabe mit Signalen zu lösen.
Wenn es tatsächlich nicht anders geht, nimm Variable.
überhaupt nie, sollte es oben heißen ...
Immer nur:
process (clk)
begin
if rising_edge(clk) then
if reset='1' then
...
else
...
end if;
end if;
end process;
> Mach ich irgendwas falsch?
Nein.
Nur gibt es in Prozessen andere syntaktische Elemente als bei
Concurrent-Zuweisungen. Und manchmal liest sich eine kombinatorische
Beschreibung dadurch einfach besser.
Du könntest deine getakteten Prozesse mit synchronem Reset noch schöner
schreiben:
1
processbegin
2
waituntilrising_edge(clk);
3
...-- "normale" Anweisungen
4
ifreset='1'then
5
...-- Resetzuweisungen: höher priorisiert, weil am Ende des Prozesses
6
endif;
7
endprocess;
Wobei "Schönheit" von Mensch zu Mensch anders definiert ist :-)
Wie werden denn eigentlich Variablen bei der Synthese verarbeitet,
einfach als (dem Datentyp entsprechend konvertierte) ungetaktete
Signale? Denn letztendlich sind es doch alles Signale, die im FPGA sind,
oder?
@Ratzeputz (Gast)
>einfach als (dem Datentyp entsprechend konvertierte) ungetaktete>Signale?
Nöö. Als Variablen ;-)
> Denn letztendlich sind es doch alles Signale, die im FPGA sind,>oder?
Physikalisch schon, aber logisch nicht.
http://www.mikrocontroller.net/articles/VHDL#Wann_und_warum_verwendet_man_Variablen.3F
Ist doch alles schon direkt und einfach aufgeschrieben :-0
> Wie werden denn eigentlich Variablen bei der Synthese verarbeitet,> einfach als (dem Datentyp entsprechend konvertierte) ungetaktete> Signale?
Du kannst auch Variable speichernd machen. Du mußt sie nur dem
entsprechend bechreiben:
1
process(clk)
2
variablevar:std_logic;
3
begin
4
ifrising_edge(clk)then
5
res1<=var;
6
var:=din;
7
res2<=var;
8
endif;
9
endprocess;
Wird hier eine Variable vor der ersten Zuweisung verwendet, muß sie
speichernd sein.
>> Denn letztendlich sind es doch alles Signale, die im FPGA sind,>>oder?>Physikalisch schon, aber logisch nicht.
Na wenn physikalisch ja, dann haben sie doch das gleiche zeitliche
Verhalten wie ungetaktet veränderte Signale, also alles geht so schnell,
wie es die Laufzeiten im FPGA erlauben?!
Dann ändern sich ihre Werte nicht "sofort" sondern halt doch so schnell
wie ungetaktete Signale, oder?
Anders gefragt, welche ungetaktete Addierung ist schneller?
Signal c <= Signal a + Signal b;
oder
Variable z := Variable x + Variable y;
?
> Anders gefragt, welche ungetaktete Addierung ist schneller?> Signal c <= Signal a + Signal b;> oder> Variable z := Variable x + Variable y;
Antwort: kann man so nicht sagen. Das hängt von der Synthese ab.
Variable sind "nur" Platzhalter für Zwischenergebnisse. Sie sind
ausserhalb eines Prozesses unbekannt. Signale werden zum "Verdrahten"
von Komponenten verwendet.
Sowohl Signale als auch Variable sind nur logische Beschreibungen
einer Verknüpfung/Berechnung. Deshalb ändern sie ihren Wert in der
Theorie sofort. Wie das allerdings in der Hardware implementiert wird,
steht dem Synthesizer frei.
Gegeben sei z.B. folgender Code, was kommt dabei heraus?
1
libraryIEEE;
2
useIEEE.STD_LOGIC_1164.ALL;
3
useIEEE.NUMERIC_STD.ALL;
4
5
entityVarSigis
6
Port(din:inSTD_LOGIC_VECTOR(3downto0);
7
dos:outSTD_LOGIC_VECTOR(3downto0);
8
dop:outSTD_LOGIC_VECTOR(3downto0);
9
dov:outSTD_LOGIC_VECTOR(3downto0));
10
endVarSig;
11
12
architectureBehavioralofVarSigis
13
signals:std_logic_vector(3downto0);
14
signalp:std_logic_vector(3downto0);
15
begin
16
process(din,s,p)
17
variablevar:std_logic_vector(3downto0);
18
begin
19
-- [1] wird parallel implementiert
20
var(0):=din(0);
21
var(1):=var(0)anddin(1);-- 2-fach AND
22
var(2):=var(1)anddin(2);-- 3-fach AND
23
var(3):=var(2)anddin(3);-- 4-fach AND
24
dov<=var;
25
26
-- [2] wird sequentiell implementiert
27
s(0)<=din(0);
28
s(1)<=s(0)anddin(1);-- 2-fach AND
29
s(2)<=s(1)anddin(2);-- 2-fach AND
30
s(3)<=s(2)anddin(3);-- 2-fach AND
31
dos<=s;
32
33
-- [3] wird parallel implementiert
34
p(0)<=din(0);-- 1:1 verbunden
35
p(1)<=din(0)anddin(1);-- 2-fach AND
36
p(2)<=din(0)anddin(1)anddin(2);-- 3-fach AND
37
p(3)<=din(0)anddin(1)anddin(2)anddin(3);-- 4-fach AND
38
dop<=p;
39
endprocess;
40
endBehavioral;
Die Ergebnisse sind in der Verhaltens-Simulation absolut identisch, dort
sind keine Laufzeiten im Spiel.
In der Praxis sind dov(0), dos(0) und dop(0) identisch als 1:1
Verbindung (Alias) ausgeführt. dov(1), dos(1) und dos(1) sind ebenfalls
gleich implementiert (2-fach AND). Ab Index 2 unterscheiden sich die
Lösungen:
die Beschreibung mit der Variablen (1] und den "ausführlich
geschriebenen" Signalen [3] ist parallel implementiert.
Die Beschreibung mit dem "mit sich selbst verknüpften" Signal [2]
sequentiell.
Dabei sind [1] und [3] identisch.
Die Laufzeit sequentieller Logik ist natürlich länger, da für das
Ergenbnis dos(3) 3 von den AND-Gattern durchlaufen werden müssen.
Lothar Miller wrote:
> Wo wir gerade so schön dabei sind:> Was macht die Synthese aus folgender Beschreibung?> Und was die Simulation?>
1
>process(din)
2
>variablevar:std_logic;
3
>begin
4
>res1<=var;
5
>var:=din;
6
>res2<=var;
7
>endprocess;
8
>
Hier die Lösung: Die Synthese setzt alle 3 Signale (din, res1 und res2)
gleich und macht einfach eine Verbindung.
Die Simulation macht etwas anderes: Mit jedem Wechsel an din wird der
prozess aufgerufen und der gespeicherte Wert von var an res1
ausgegeben.
Und es hilft nichts: var kann nicht in die Sensitivity-List des
Prozesses aufgenommen werden (Syntax-Fehler).
Fazit: Vorsicht mit Variablen ;-)
Ok, letzte Frage zur Klärung:
Gibt es etwas, was man in der Synthese(!) NICHT mit Signalen, seien sie
getaktet oder ungetaktet, hinkriegt, wofür man unbedingt Variablen
braucht? Oder lässt sich letztendlich alles auf std_logic-Signale
zurückführen?
> Gibt es etwas, was man in der Synthese(!) NICHT mit Signalen, seien sie> getaktet oder ungetaktet, hinkriegt
Ja, sicher. VHDL lässt dich sehr viel mehr hinschreiben als
synthetisierbar ist.
> , wofür man unbedingt Variablen braucht?
Nein. Was mit Signalen nicht synthetisierbar ist, das geht auch mit
Variablen nicht.
> Oder lässt sich letztendlich alles auf std_logic-Signale zurückführen?
Alles was synthetisierbar ist, ja.
> Gibt es etwas, was man in der Synthese(!) NICHT mit Signalen, seien> sie getaktet oder ungetaktet, hinkriegt, wofür man unbedingt Variablen> braucht?
Nein, nur lässt sich mit Variablen u.U. eine Logik kompakter
beschreiben.
Zum Schluss wird die beschriebene Hardware im FPGA in LUTs und FFs
abgebildet. Was sich darauf nicht abbilden lässt, lässt sich nicht
realisieren.
Wobei es dabei natürlich Ausnahmen gibt, in Form von speziellen
Hardwarkomponenten, die aber idR. von Hand instantiiert werden müssen
(DDR-FFs, Serielle Sender und Empfänger, Prozessorkerne...).
@ Morin:
>> Gibt es etwas, was man in der Synthese(!) NICHT mit Signalen, seien sie>> getaktet oder ungetaktet, hinkriegt> Ja, sicher. VHDL lässt dich sehr viel mehr hinschreiben> als synthetisierbar ist.
Das stimmt schon, aber hast du da nicht den Zusammenhang verloren?
M.E. ist die Fragestellung eine andere ;-)
Es geht darum, ob man irgendwelche Sachen nur mit Variablen
beschreiben könnte.
> Das stimmt schon, aber hast du da nicht den Zusammenhang verloren?
In gewisser Hinsicht ja, aber andersrum wäre die Antwort evtl
mißverständlich gewesen :/ Naja, hat ja jeder verstanden, was gemeint
war.
>Autor: Falk Brunner (falk)>Datum: 25.11.2008 10:18>> Denn letztendlich sind es doch alles Signale, die im FPGA sind,>>oder?>>Physikalisch schon, aber logisch nicht.
So ein Schwachsinn. Wenn du nur rumschwurbeln willst, halt bitte die
Klappe.
>http://www.mikrocontroller.net/articles/VHDL#Wann_...>Ist doch alles schon direkt und einfach aufgeschrieben :-0
Du musst es ja noetig haben. Stinkts bei dir nicht gewaltig vor lauter
Eigenlob?
Einfach im Sinne von primitiv ist es schon, da gebe ich dir recht. Aber
in der Praxis vollkommen unbrauchbar.
Was ist dir denn für ne Laus über die Leber gelaufen? :)
> >Physikalisch schon, aber logisch nicht.> So ein Schwachsinn. Wenn du nur rumschwurbeln willst, halt bitte die> Klappe.
Wie du dir sicher denken kannst, meinte Falk damit, dass man durchaus in
anderen Konstrukten (z.B. Variablen) das Design beschreibt, während
letztendlich alle Hardwarebeschreibungen in Netzlisten mit Signalen (und
ohne Variablen) umgewandelt werden, bevor die endgültige Synthese
stattfindet.
> Du musst es ja noetig haben. Stinkts bei dir nicht gewaltig vor lauter> Eigenlob?> Einfach im Sinne von primitiv ist es schon, da gebe ich dir recht. Aber> in der Praxis vollkommen unbrauchbar.
Hier basiert alles auf freiwilliger Mitarbeit. Du hast also keinerlei
Ansprüche zu stellen. Lern lieber erst mal, dich zu benehmen.
Lothar M. schrieb:> Du könntest deine getakteten Prozesse mit synchronem Reset noch schöner> schreiben:process begin> wait until rising_edge(clk);> ... -- "normale" Anweisungen> if reset='1' then> ... -- Resetzuweisungen: höher priorisiert, weil am Ende des> Prozesses> end if;> end process;
Ich versuche gerade mir das "höher priorisiert, weil am Ende des
Prozesses" durch weitere Literatur klarer zu machen, denn es
widerspricht doch etwas meiner Intuition. Bei einem if, wie im Beispiel
darüber, ist ja wohl das oberste Statement priorisiert, insofern sollten
sich die beiden Implementierungen von der Priorisierung nicht
unterscheiden.
Ich konnte aber bislang nichts finden, wo die Priorisierung von
Concurrent-Zuweisungen beschrieben ist (vermutlich hab' mich noch nicht
die richtigen Suchworte verwendet) - kann jemand mir 'nen Link auf
entsprechende Beschreibungen geben?
U.G. L. schrieb:> denn es widerspricht doch etwas meiner Intuition.
Es ist einfach so, dass sich der Wert eines Signals während des
Prozesses nicht ändert, sondern der im Verlauf des Prozesses gern auch
wiederholt neu berechnete Wert dem Signal erst am Ende des Prozesses
zugewiesen wird.
> Ich konnte aber bislang nichts finden, wo die Priorisierung von> Concurrent-Zuweisungen beschrieben ist
Wie der Name schon sagt, gibt es da keine Priorisierung, weil die
Zuweisungen ja "nebenläufig", also "gleichzeitig", stattfinden.
> Bei einem if, wie im Beispiel darüber, ist ja wohl das oberste> Statement priorisiert
Weil die if-Abfrage einen neuen Block markiert, ist dieses "die letzte
Zuweisung an ein Signal gewinnt" da natürlich nachrangig, weil ein Teil
der Zuweisungen gar nicht durchlaufen wird.
Mal abseits der ganze Theorie ein Beispiel:
1
processbegin
2
waituntilrising_edge(clk);
3
signalA<='1';
4
signalA<='0';
5
endprocess;
Klar, dass dabei das signalA niemals einen Wert ungleich '0' einnehmen
wird.
Jetzt das:
1
processbegin
2
waituntilrising_edge(clk);
3
signalA<='1';
4
ifsignalA='1'then
5
signalB<=notsignalB;
6
endif;
7
signalA<='0';
8
endprocess;
Hier wird das signalB niemals toggeln, weil das signalA immer den Wert
'0' hat ("die letzte Zuweisung gewinnt").
Und das ganze Concurrent:
1
signalA<='1';
2
signalA<='0';
Das gibt einen Fehler, weil einem Signal gleichzeitig unterschiedliche
Werte zugewiesen werden.
Ok - da hat mich dann wohl das Wörtchen "priorisiert" auf einen
"Holzweg" gelenkt :-).
In der Praxis werde ich keine sich widersprechende Angaben haben, die
"priorisiert" werden müssen, sondern bestenfalls sich ergebende
"Aktualisierungen", etwa wenn ich einen Default-Wert vorgebe und eine
Berechnung diesen überschreibt.
U.G. L. schrieb:> etwa wenn ich einen Default-Wert vorgebe und eine Berechnung diesen> überschreibt.
Das ist letztlich auch nur eine Priorisierung, denn der berechnete Wert
hat höhere Priorität als der Defaultwert.
U.G. L. schrieb:> process begin> wait until rising_edge(clk);> ... -- "normale" Anweisungen> if reset='1' then> ... -- Resetzuweisungen: höher priorisiert> end if;> end process;> .....> Ich konnte aber bislang nichts finden, wo die Priorisierung von> Concurrent-Zuweisungen beschrieben ist
Das sind auch keine 'concurrent statements', sondern 'sequential
statements' da sie in einem Prozess stehen.
Bei 'concurrent' darfst du (ausserhalb eines Prozesses) ein Signal genau
an einer Stelle beschreiben.
Bei 'sequential' (innerhalb eines Prozesses) wird alles brav nach
Reihenfolge abgearbeitet, du darfst X-mal das Signal innerhalb des
Prozesses beschreiben. Und die letzte gueltige Zuweisung (die ganzen
'if' oder 'case') gewinnt dann.
Deshalb gewinnt evtl. der oben gezeigte reset='1' und ueberschreibt
alles, was da vorher steht.
Dein Stichwort in diesem Fall ist also 'sequential statement'
"concurrent" hatte ich Lothars Beiträgen entnommen und übersehen, dass
er das (vermutlich) nicht auf die Anordnung innerhalb eines process
gemünzt hatte. Das "priorisiert" hatte bei mir den Eindruck erwegt, dass
es eine Regel/Definition gibt, von der ich nichts weiss - mittlerweile
ist mir klar, dass es diese Regel nicht gibt bzw. geben muss, weil die
"Priorisierung" eben durch die "sequential" Bearbeitung zustande kommt.
Eine Frage von einem Anfänger.
>In der Simulation, wo ich ja mal den gesamten Syntaxumfang von VHDL ausschöpfen
darf, sind mir Variablen gern gesehen.
Demzufolge schreibst du deine architectures zweimal? Einmal um es
schnell zu simulieren und wenn es dann läuft schreibst du es komplett
neu doch dieses Mal ohne Variablen? Warum sollte man nicht direkt alles,
außer der Testbench, in synthetisierbarer Form aufschreiben?
Fragr schrieb:> Demzufolge schreibst du deine architectures zweimal?
Nein. Dieser Schluss ist falsch.
> Warum sollte man nicht direkt alles, außer der Testbench, in> synthetisierbarer Form aufschreiben?
Mit "in der Simulation" meine ich "in der Testbench".
Denn natürlich macht eine Simulation nur dann Sinn, wenn man genau die
Beschreibung simuliert, die letztlich auf das FPGA synthetisiert wird.
Und natürlich gilt was ich gleich danach schrieb:>>> Auch zur Beschreibung und Bearbeitung von Schleifen in der Synthese sind>>> sie (oft) unumgänglich.