mikrocontroller.net

Forum: FPGA, VHDL & Co. Variable vs Signal


Autor: thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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:
  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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Etwas OT:
Dieses "Vergessen" von Signalen passiert übrigens recht gern und z.B. 
auch im Beispiel:
http://toolbox.xilinx.com/docsan/xilinx4/data/docs...

Dort ist im Prozess SIG das Signal D vergessen worden.
 SIG:process (A,B,C) 
   :
        X <= C xor D; 
   :
        Y <= C xor D; 
Fazit: Hardware ok, Simulation falsch   :-o

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lothar Miller (lkmiller)

>Versuche, die Aufgabe mit Signalen zu lösen.
>Wenn es tatsächlich nicht anders geht, nimm Variable.

GENAU!

Autor: thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab solche Prozesse mit was anderem als das Taktsignal in der 
Sensitivity-List eigentlich überhaupt ... Mach ich irgendwas falsch?

Grüße
thomas

Autor: thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ü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;

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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:
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;

Wobei "Schönheit" von Mensch zu Mensch anders definiert ist :-)

Autor: Ratzeputz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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_...

Ist doch alles schon direkt und einfach aufgeschrieben :-0

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
> 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:
  process(clk)
  variable var: std_logic;
  begin
     if rising_edge(clk) then
        res1 <= var;
        var  := din;
        res2 <= var;
     end if;
  end process;
Wird hier eine Variable vor der ersten Zuweisung verwendet, muß sie 
speichernd sein.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo wir gerade so schön dabei sind:
Was macht die Synthese aus folgender Beschreibung?
Und was die Simulation?
  process(din)
  variable var: std_logic;
  begin
     res1 <= var;
     var  := din;
     res2 <= var;
  end process;

Autor: Ratzeputz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> 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;

?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity VarSig is
    Port ( din : in   STD_LOGIC_VECTOR (3 downto 0);
           dos : out  STD_LOGIC_VECTOR (3 downto 0);
           dop : out  STD_LOGIC_VECTOR (3 downto 0);
           dov : out  STD_LOGIC_VECTOR (3 downto 0));
end VarSig;

architecture Behavioral of VarSig is
signal s : std_logic_vector(3 downto 0);
signal p : std_logic_vector(3 downto 0);
begin
   process(din, s, p) 
   variable var : std_logic_vector(3 downto 0);
   begin
      -- [1] wird parallel implementiert
      var(0) :=            din(0);
      var(1) := var(0) and din(1); -- 2-fach AND
      var(2) := var(1) and din(2); -- 3-fach AND
      var(3) := var(2) and din(3); -- 4-fach AND
      dov <= var;
      
      -- [2] wird sequentiell implementiert 
      s(0) <=          din(0);
      s(1) <= s(0) and din(1); -- 2-fach AND
      s(2) <= s(1) and din(2); -- 2-fach AND
      s(3) <= s(2) and din(3); -- 2-fach AND
      dos  <= s;
      
      -- [3] wird parallel implementiert 
      p(0) <= din(0);                                  -- 1:1 verbunden
      p(1) <= din(0) and din(1);                       -- 2-fach AND
      p(2) <= din(0) and din(1) and din(2);            -- 3-fach AND
      p(3) <= din(0) and din(1) and din(2) and din(3); -- 4-fach AND
      dop  <= p;
   end process;
end Behavioral;
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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller wrote:
> Wo wir gerade so schön dabei sind:
> Was macht die Synthese aus folgender Beschreibung?
> Und was die Simulation?
>
>   process(din)
>   variable var: std_logic;
>   begin
>      res1 <= var;
>      var  := din;
>      res2 <= var;
>   end process;
> 
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 ;-)

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Lothar Miller (lkmiller)

>Fazit: Vorsicht mit Variablen ;-)

GAAAANZ neue Erkenntnis! ;-)

Autor: Ratzeputz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Morin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Ratzeputz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Richtig, Lothar, so war es gemeint. Und danke für eure Antworten zur 
Klärung. :)

Autor: Morin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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: Xilitera (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

Autor: Morin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: U.G. L. (dlchnr)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
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:
  process begin
     wait until rising_edge(clk);
     signalA <= '1';
     signalA <= '0';
  end process;
Klar, dass dabei das signalA niemals einen Wert ungleich '0' einnehmen 
wird.
Jetzt das:
  process begin
     wait until rising_edge(clk);
     signalA <= '1';
     if signalA='1' then
        signalB <= not signalB;
     end if;
     signalA <= '0';
  end process;
Hier wird das signalB niemals toggeln, weil das signalA immer den Wert 
'0' hat ("die letzte Zuweisung gewinnt").

Und das ganze Concurrent:
   signalA <= '1';
   signalA <= '0';
Das gibt einen Fehler, weil einem Signal gleichzeitig unterschiedliche 
Werte zugewiesen werden.

: Bearbeitet durch Moderator
Autor: U.G. L. (dlchnr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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'

Autor: dlchnr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.