Hallo allerseits,
ich erlerne nach und nach anhand von mehreren Websites VHDL. Eine von
den Sachen, die mir unklar sind, ist der Process. In allen Quellen, die
ich dazu gefunden habe heißt es, enthält ein Process sequentielle
Anweisungen, die nach Aktivierung des Processes ähnlich wie bei
gewöhnlichen Programmiersprachen nacheinander ausgeführt werden. Aber
mir ist nicht klar, was genau ich darunter vorstellen muss. Nach einer
ausführlicheren Erklärung habe ich bisher vergeblich gesucht. Kann mir
vielleicht jemand von euch das klar machen?
Was heißt es denn jetzt genau "nacheinander ausgeführt" z.B. in diesem
Code hier:
1
entityAND_OR_XORis
2
port(A,B:inbit;
3
Z_OR,Z_AND,Z_XOR:outbit);
4
endAND_OR_XOR;
5
6
architectureRTLofAND_OR_XORis
7
begin
8
9
A_O_X:process(A,B)
10
begin
11
Z_OR<=AorB;
12
Z_AND<=AandB;
13
Z_XOR<=AxorB;
14
endprocessA_O_X;
15
16
endRTL;
Heißt es, dass beim ersten Takt nach der Aktivierung des Prozesses hier
der Ausgang Z_OR den Zustand entsprechen dem Ergebnis des Ausdrucks A or
B annimmt. Beim zweiten Takt nimmt der Ausgang Z_AND den Wert A and B an
und beim dritten Takt entsprechend Z_XOR <= A xor B. Unter
sequentieller Ausführung würde ich nur so ein Verhalten verstehen.
Allerdings habe ich aus meinen bisherigen Programmierversuchen eher den
Eindruck, dass in diesem Prozess alle drei Ausgänge gleichzeitig den
Wert der entsprechend zugewiesenen logischen Verknüpfung annehmen.
Was stimmt denn jetzt in Wirklichkeit und was bedeutet in diesem Fall
"sequentielle Anweisung"?
Danke schon mal für die Mühe!!
Hey,
Das sollte ein kombinatorische Prozess sein sobalt sich die die Signale
in der Sensitivity List ändern wird alles im Process kombinatorisch
ausgeführt.
Ist in diesem Fall also quasi nur eine besser lesbare Beschreibung für
ein Kombinatorisches Verhalten.
> Dieser Prozess hat mit Takten wenig zu tun.
Diesen Code habe eins zu eins einfach von dieser Seite kopiert:
http://www.vhdl-online.de/tutorial/englisch/t_40.htm#pgfId-1015035
Und die Erklärungen die neben bzw. unter diesem Code auf der Seite
stehen (sich dann also auch auf diesen Code beziehen), sagen dass die
Anweisungen im Prozess nacheinander ausgeführt werden.
Wie TM bereits gesagt hat: Das Beispiel ist kein getakteter Process,
sondern nur ein kombinatorischer Process. Alle Zuweisungen werden daher
immer gleichzeitig ausgeführt! Dein Beispiel soll nur den Gebrauch der
Sensitivy List verdeutlichen!
Danke für die Atnworten!
Sagen wir mal, der Prozess würde so aussehen:
1
A_O_X:process(clk,rst)
2
begin
3
ifrst='0'then
4
Z_OR<='0';
5
Z_AND<='0';
6
Z_XOR<='0';
7
elsifrising_edge(clk)then
8
Z_OR<=AorB;
9
Z_AND<=AandB;
10
Z_XOR<=AxorB;
11
endif;
12
endprocessA_O_X;
Werden hier dann die drei Zuweisungen jeweils nacheinander im Abstand
von einem Takt ausgeführt oder werden sie in einem einzigen Takt
gleichzeitig ausgeführt?
enan schrieb:> nur der reset sollte asynchron sein.
Ja, nun. Das gerade nicht...
Siehe den Beitrag "vhdl-richtlinien f. synthese?">>> A_O_X: process (A, B)
Der Prozess muss neu berechnet werden, wenn sich A bzw. B irgendwie
ändern.
Und dann geht es los:
>>> begin>>> Z_OR <= A or B;>>> Z_AND <= A and B;>>> Z_XOR <= A xor B;>>> end process A_O_X ;
In der (virtuellen) Zeit 0 wird der Prozess duchlaufen und am Ende des
Prozesses die Werte an die entsprechenden Signale zugewiesen.
In der realen Welt werden dafür dann einfach 3 Gatter erzeugt, an die
parallel die beiden Eingangssignale angeschlossen sind.
noips schrieb:> sagen dass die Anweisungen im Prozess nacheinander ausgeführt werden.
Sie werden lediglich in der Simulation nacheinander berechnet. In der
Hardware existieren 3 getrennte Gatter. Die Hardware ist exakt die selbe
wie bei dieser Beschreibung:
noips schrieb:> Sagen wir mal, der Prozess würde so aussehen:A_O_X: process (clk, rst)> ...> Werden hier dann die drei Zuweisungen jeweils nacheinander im Abstand> von einem Takt ausgeführt oder werden sie in einem einzigen Takt> gleichzeitig ausgeführt?
Sie werden deshalb gleichzeitig ausgeführt, weil ein Prozess in der
Zeit 0 berechnet wird.
Wenn also ein Takt kommt, werden alle 3 Ergebnisse gleichzeitig neu
berechnet. Diese Berechnung erfolgt nur auf dem Simulationsrechner
nacheinander, währenddessen läuft aber die Simulationszeit nicht weiter!
Besten Dank für die Antworten!
Lothar Miller schrieb:> In der> Hardware existieren 3 getrennte Gatter. Die Hardware ist exakt die selbe> wie bei dieser Beschreibung:
Genau so habe ich es mir vorgestellt. Diese Erklärungen mit der
sequentiellen Abarbeitung hat mich nur durcheinander gebracht. Dann
beziehen sich die Erklärungen ja nur auf das Verhalten in der Simulation
und nicht auf die synthetisierte Hardware, sehe ich es jetzt richtig?
noips schrieb:> Dann beziehen sich die Erklärungen ja nur auf das Verhalten> in der Simulation und nicht auf die synthetisierte Hardware,> sehe ich es jetzt richtig?
Ja.
Für die Simulation ist eine korrekte Sensitivliste unbedingt nötig. Wenn
du mal diese Beschreibung nimmst:
1
entityAND_OR_XORis
2
port(A,B,CLK:inbit;
3
Z_OR,Z_AND,Z_XOR:outbit);
4
endAND_OR_XOR;
5
6
architectureRTLofAND_OR_XORis
7
begin
8
9
A_O_X:process(CLK)
10
begin
11
Z_OR<=AorB;
12
Z_AND<=AandB;
13
Z_XOR<=AxorB;
14
endprocessA_O_X;
15
16
endRTL;
Dann sieht das in der Simulation so aus, als ob das Ergebnis irgendwas
mit CLK zu tun hätte, denn nur bei einer Änderung von CLK ändert sich
das Ergebnis.
Die Synthese wird dir aber nur ein paar Infos zum Thema
"unvollständige Sensitivliste" ausgeben und dann die nötigen 3 Gatter
erzeugen.
Fazit: Simulation falsch... :-o
noips schrieb:
>Genau so habe ich es mir vorgestellt. Diese Erklärungen mit der>sequentiellen Abarbeitung hat mich nur durcheinander gebracht. Dann>beziehen sich die Erklärungen ja nur auf das Verhalten in der Simulation>und nicht auf die synthetisierte Hardware, sehe ich es jetzt richtig?
Wenn Du mit Variablen arbeitest, dann stimmt wiederum der Ausdruck
sequentielle Abarbeitung. Eine Variable kann einen Zustand annehmen und
danach kann wieder von ihr gelesen werden.
A_O_X: process (clk, rst)
variable Var_B : std_logic;
begin
if rst = '0' then
A <= '0';
B <= '0';
C <= '0';
elsif rising_edge (clk) then
B <= A or B;
C <= B; -- Zustand um einen Takt älter als A
Var_B := A or B;
A <= Var_B; -- Zustand um einen Takt schneller als C
end if;
end process A_O_X ;
variable Var_Intern_2 : PRBS_REGISTER;
Eine weitere Sache die mir spontan einfällt: wenn beispielsweise in
Zeile 10 ein Signal A den Zustand 1 einnehmen soll und in Zeile 100
wiederum den Zustand 2, dann wird die Zeile 10 ignoriert!
A_O_X: process (clk, rst)
begin
if rst = '0' then
A <= '0';
elsif rising_edge (clk) then
A <= '0'; -- Zuweisung 1 wird von Zuweisung 2 aufgehoben
............
A <= '1';
end if;
end process A_O_X ;
brando schrieb:> Wenn Du mit Variablen arbeitest, dann stimmt wiederum der Ausdruck> sequentielle Abarbeitung. Eine Variable kann einen Zustand annehmen und> danach kann wieder von ihr gelesen werden.
Allerdings erscheint auch hier ein "Zwischenwert" niemals in der realen
Hardware. Die Signalzuweisung erfolgt immer am Ende des Prozesses, der
wiederum in der Zeit 0 abgearbeitet wird...
1
elsifrising_edge(clk)then
2
B<=AorB;
3
C<=B;-- Zustand um einen Takt älter als A
4
endif;
Es wird der gesamte Prozess mit den "alten" Werten von A, B und C
druchgerechnet. Deshalb gibt das hier eigentlich 2 Prozesse:
1
process...
2
ifrising_edge(clk)then
3
B<=AorM;
4
endif;
5
6
process...
7
ifrising_edge(clk)then
8
C<=B;-- Zustand um einen Takt älter als A
9
endif;
Und jetzt ist klar: mit der nächsten steigenden Flanke wird der aktuelle
Wert von B nach C geschrieben. Und es wird ein neuer Wert für B aus A
und M berechnet.
brando schrieb:> Eine weitere Sache die mir spontan einfällt: wenn beispielsweise in> Zeile 10 ein Signal A den Zustand 1 einnehmen soll und in Zeile 100> wiederum den Zustand 2, dann wird die Zeile 10 ignoriert!
Also stimmt auch hier der Begriff sequentielle Abarbeitung... :-o
BTW:
if rst = '0' then
A <= '0';
B <= '0';
C <= '0';
elsif rising_edge (clk) then
B <= A or B;
Das ist ein "Selbsthalter"... ;-)
Wenn A irgendwann mal '1' wird, dann bleibt B fürderhin '1'...
Hallo,
ich hätte zu diesem Thema auch noch eine kleine Frage und zwar genau
dann wenn ich z.B. 10 Variablen in meinem Prozess habe.
Nun hab ich einen relativ hohen Clock (beispielsweise 100 MHz) in der
Sensitivitätsliste, mache aber eine relativ große Berechnung in diesem
Prozess. Da die Variablen ja nun wirklich sequentiell abgearbeitet
werden ist dies ja nicht immer komplett gleichzeitig in Gattern
auszuführen bzw. benötigt evtl mehr Zeit als die Periodendauer meines
Clocks.
Was passiert wenn ein neues Clock-Event auftaucht die vorherige
Berechnung aber noch nicht abgeschlossen ist? Ist der Prozess dann
gesperrt (ähnlich wie ein Mutex in C) und ich verpasse eventuell ein
Clockevent oder wird der laufende Prozess einfach unterbrochen und neu
gestartet?
Falls dem so ist wie lässt sich dieses Problem beseitigen, ist hier
Pipelining das richtige Stichwort und spricht man bei so einem Problem
generell von Timing Problemen im FPGA?
Mich interessiert hier hauptsächlich die synthetisierte Version, also
das Verhalten im bspw. einem FPGA. Ich denke mit reiner Simulation
lassen sich Probleme dieser Art nicht erkennen bzw vernünftig lösen...
Vielen Dank.
Benson
Ben G.. schrieb:> Da die Variablen ja nun wirklich sequentiell abgearbeitet> werden ist dies ja nicht immer komplett gleichzeitig in Gattern> auszuführen bzw. benötigt evtl mehr Zeit als die Periodendauer meines> Clocks.
Doch. Die Variablen werden ebenfalls garantiert parallel in Gatter
abgebildet. Evtl. eben in mehreren Logikebenen hintereinander.
Ein Process (mit nur einem Takt bzw. wait) wird immmer in der
theoretischen Zeit 0 abgearbeitet. Und das geht in der Realität nur,
wenn keine 2. Registerebene vorhanden ist.
> Was passiert wenn ein neues Clock-Event auftaucht die vorherige> Berechnung aber noch nicht abgeschlossen ist?
Dann ist dein Takt einfach zu schnell für dein Design. Und dann kann
alles passieren...
Aber dann hattest du deine Timing-Constraints (wenigstens die
Taktfrequenz) nicht richtig gesetzt. Denn sonst hätte die Implementation
herumgemeckert, dass dein Design die gewünschte Frequenz nicht erreicht.
> Falls dem so ist wie lässt sich dieses Problem beseitigen, ist hier> Pipelining das richtige Stichwort und spricht man bei so einem Problem> generell von Timing Problemen im FPGA?
Ja, Pipelining heißt erst mal, dass mehrere "Zwischenregister"
eingeführt werden, vor die jeweils nur soviel Logik kommt, dass der
entsprechende Logikpfad schnell genug ist.
Ein Stichwort dazu ist auch "Register Balancing". Damit werden
"automatisch" weitere Registerstufen eingeführt...
> Ich denke mit reiner Simulation> lassen sich Probleme dieser Art nicht erkennen bzw vernünftig lösen...
Eine Timing-Simulation könnte das aufdecken. Aber wie gesagt: vernünftig
gesetzte Timing-Constraints zeigen solche Fehler schon bei der
Implementation auf.
Ben G.. schrieb:> Hallo,>> ich hätte zu diesem Thema auch noch eine kleine Frage und zwar genau> dann wenn ich z.B. 10 Variablen in meinem Prozess habe.> Nun hab ich einen relativ hohen Clock (beispielsweise 100 MHz) in der> Sensitivitätsliste, mache aber eine relativ große Berechnung in diesem> Prozess. Da die Variablen ja nun wirklich sequentiell abgearbeitet> werden ist dies ja nicht immer komplett gleichzeitig in Gattern> auszuführen bzw. benötigt evtl mehr Zeit als die Periodendauer meines> Clocks.> Was passiert wenn ein neues Clock-Event auftaucht die vorherige> Berechnung aber noch nicht abgeschlossen ist? Ist der Prozess dann> gesperrt (ähnlich wie ein Mutex in C) und ich verpasse eventuell ein> Clockevent oder wird der laufende Prozess einfach unterbrochen und neu> gestartet?
Das ist dann eine Timing Violation. Was passiert ist ein Griff in die
Flip-Flop-Wundertüte, mal schaltet es mal schaltet es nicht, mal ist es
0 mal ist es 1.
Ben G.. schrieb:> Was passiert wenn ein neues Clock-Event auftaucht die vorherige> Berechnung aber noch nicht abgeschlossen ist? Ist der Prozess dann> gesperrt (ähnlich wie ein Mutex in C) und ich verpasse eventuell ein> Clockevent oder wird der laufende Prozess einfach unterbrochen und neu> gestartet?
Die Anzahl der Variablen, bzw. die Anzahl der Anweisungen hat nichts zu
sagen. Die Anweisungen werden NUR bei der Simulation wie eine
Programmiersprache sequentiell ausgeführt und die Simulation läuft dann
einfach langsamer.
Bei der Synthese wird eine Verschaltung des FPGA's erzeugt, bei der sich
alle Signale gleich WIE IN DER SIMULATION verhalten. Diese Verschaltung
kann mehr oder weniger komplex sein und dabei kann es manchmal
passieren, dass doe internen Bauteile des FPGA's (jedes davon hat einen
bestimmte Durchlaufzeit) so miteinander verschalten werden müssen, dass
die Hardware zu langsam ist. In diesem Falle funktionieren Teile der
Schaltung nicht korrekt, weil die Eingänge der Flipflops zum Zeitpunkt
der Taktflanke noch nicht den korrekten Wert haben.
Das hat aber mit dem Durchlaufen des Prozesses nichts zu tun.
Vielen Dank für die Antworten. Dann muss ich gestehen das ich den Aspekt
der Timing Contraints immer etwas vor mir hergeschoben habe. Vom Prinzip
her habe ich in die richtige Richtung gedacht, aber ich bin mal "gut
Glück" davon ausgegangen das der FPGA schnell genug sein wird und die FF
schnell genug schalten.
Ich habe das Thema Timing Constraints mal grob angeschnitten, allerdings
war das Manual von Altera hierzu ziemlich mächtig. Prinzipiell benutze
ich da den Time Quest Analyzer, wenn ich bspw 3 verschiedene Clocks von
einer PLL erzeugen lasse gebe ich ja im Time Quest Analyzer die Daten zu
den einzelnen Clocks an und weise sie den einzelnen Signale in meinem
Design zu. Gibt es hierzu noch spezielle Dinge zu beachten bzw. Verweise
auf gut erklärte Beispiele?
Wird denn bei der Synthese des Designs tatsächlich auch hinsichtlich der
Angaben der Timing Constraints optimiert? Also in Bezug auf Anordnung
der einzelnen Register etc, Signallaufzeiten usw. ?
Achja: Ich gebe zu die "Critical Warnings" bezüglich der fehlenden
Timing Contraints in Quartus hab ich bewusst übersehen...Aber ich werde
mich wohl ausführlicher darum kümmern.
Ben G.. schrieb:> Wird denn bei der Synthese des Designs tatsächlich auch hinsichtlich der> Angaben der Timing Constraints optimiert?
Nicht bei der Synthese ...
> Also in Bezug auf Anordnung der einzelnen Register etc,> Signallaufzeiten usw. ?
... aber beim Place&Route. Gut erkannt.
> wenn ich bspw 3 verschiedene Clocks von einer PLL erzeugen lasse gebe ich> ja im Time Quest Analyzer die Daten zu den einzelnen Clocks an und weise> sie den einzelnen Signale in meinem Design zu.
Hört sich nach statischer Timinganalyse an...
Das wäre allerdings zu spät, denn dort wird das Design nur auf die
Einhaltung von Timings kontrolliert. Vorgaben für das Design macht
man schon früher im Constraints-File.
Das Constraints-File hängt aber von der Entwicklungsumgebung ab? Oder
ist dies tatsächlich ein standardisiertes File welches ich selbst
erstellen muss?
Ich habe nämlich nun unter Quartus im Time Quest Analyzer relativ
komfortabel die Constraints gesetzt und in den Settings meines Projekts
das automatisch erzeugte .sdc- File hinzugefügt.
Da ich die ALTPLL-Komponente benutze war er mit folgenden 2 Zeilen in
der tcl Kommandozeile vollkommen zufrieden:
derive_pll_clocks -create_base_clocks
derive_clock_uncertainty
Wenn ich nun mein Projekt erneut compiliere sollte er doch beim
Place&Route auf die Constraints-Vorgaben hin optimieren?
Die Critical Warnings sind nun abgeändert in "Timing requirements not
met", was wohl auch stimmt da das Verhalten des FPGA's nicht mit der
Simulation übereinstimmt.
Ben G.. schrieb:> Das Constraints-File hängt aber von der Entwicklungsumgebung ab?
Ja, da kocht jeder Hersteller sein eigenes Süppchen...
> Wenn ich nun mein Projekt erneut compiliere sollte er doch beim> Place&Route auf die Constraints-Vorgaben hin optimieren?
Die Tools werden nun (abhängig von Optimierungseinstellungen mehr oder
weniger gut) versuchen, deine Vorgaben einzuhalten. Wenn sie das nicht
schaffen, passiert sowas:
> Die Critical Warnings sind nun abgeändert in "Timing requirements not> met", was wohl auch stimmt da das Verhalten des FPGA's nicht mit der> Simulation übereinstimmt.
Ja, das Verhalten des FPGAs ist unbestimmt, wenn das Timing nicht
eingehalten werden kann.
Ich habe nun alle Constraints gesetzt. Nun habe ich insgesamt 4 Prozesse
in meinem Design.
Ein Prozess davon soll eine Division von 2 16 bit Integer Zahlen
durchführen. Ich habe den Prozess soweit möglich von allen anderen
arithmetischen operationen befreit, aber selbst mit einem Clock von 1
MHz habe ich immer noch Probleme mit dem Timing, bzw. bekomme immer ein
Critical Warning "Timing requirements not met"
Ich habe auch schon versucht die Division in optimierter Floating Point
Division durchzuführen, dies brachte auch keinen Erfolg.
Hat hierzu jmd brauchbare Hinweise, auch wenn dies nun etwas off topic
gerät...