Forum: FPGA, VHDL & Co. vhdl anfängerfrage


von Michael W. (Gast)


Lesenswert?

Ich habe nun begonnen, mich mit VHDL zu beschäftigen, habe mir den 
Reichardt angeschafft (bis zur hälfte "gelesen") und modelsim 
installiert.

Obwohl ich bereits in der Lage bin, einfachere Aufgaben zu bewältigen, 
habe ich immer so ein komisches Gefühl dabei, da ich nie weiß, ob ich es 
auch "richtig" mache.

Bei einem Programm für eine CPU kann ich besser abschätzen, was gut und 
schlecht sein wird, während ich keine Ahnung habe, was aus einem VHDL 
Entwurf nach der Synthese herauskommt.

Beispiel:
1
library IEEE;
2
use IEEE.std_logic_1164.all;
3
use IEEE.numeric_std.all;
4
5
entity counter is
6
  port (count : buffer bit_vector(8 downto 1);
7
    clk   : in bit;
8
    reset : in bit);
9
end;
10
11
architecture only of counter is
12
  constant tpd_reset_to_count : time := 3 ns;
13
  constant tpd_clk_to_count   : time := 2 ns;
14
15
  function increment(val : bit_vector) return bit_vector
16
  is
17
    -- normalize the indexing
18
    alias input : bit_vector(val'length downto 1) is val;
19
    variable ucount: unsigned(val'length downto 1) := unsigned(To_StdLogicVector(val));
20
  begin
21
    if ucount < 10 then
22
       ucount := ucount + 1;
23
    else
24
       ucount := to_unsigned(3, val'length);
25
    end if;
26
    return To_bitvector(std_logic_vector(ucount));
27
  end increment;
28
begin
29
30
  ctr:
31
  process(clk, reset)
32
  begin
33
    if (reset = '1') then
34
      if reset'event then
35
        count <= (others => '0') after tpd_reset_to_count;
36
      end if;
37
    elsif clk'event and (clk = '1') then
38
      if (count = "10000111") then
39
         count <= "00000000";
40
      else
41
        count <= increment(count) after tpd_clk_to_count;
42
      end if;
43
    end if;
44
  end process;
45
46
end only;

Als Spielerei (!!) habe ich ein Beispiel so umgebaut, dass die Funktion 
mit unsigned statt bit_vector variablen rechnet. So kann ich bis 10 
Zählen und setze dann den Zähler wieder auf 3. Das ginge auch anders mit 
"00001010" und "00000011" und einem bit_vector.  Wie wirkt sich das nun 
aus? Ich tue mir schwer vorzustellen, wie die Variablen einer Funktion, 
die in einem Prozess verwendet wird umgesetzt werden. Wie werden z.B. 
Konvertierungsfunktionen umgesetzt? Als vordefinierte Einheit, die dann 
eingebunden wird?

Gibt es hier allgemeine Regeln oder ist alles bloß Erfahrung?

Danke und Grüße
Michael

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Ohne zu Dir und Deinen Code-Überlegungen im Detail Stellung nehmen zu 
wollen, erlaube ich mir die Bemerkung, dass die Art der Annäherung an 
das Thema VHDL sagen wir mal, "ungewöhnlich" ist!

Wenn ich mir vorstelle, dass ein simples count Problem wie dieses, 
demnächst generell so gelöst wird, bzw der Code von vielen Entwicklern 
so aussieht, dann schwanke ich zwischen Erschiessen und Erhängen.

Ein kleiner Exkurs dazu: In der Industrie kommt es darauf an, ein 
Problem möglichst vollständig und dabei einfach und schnell zu lösen. 
Eine jede Beschreibung (und VHDL ist hier eine Beschreibung einer 
Problemlösung) sollte demgemäss einfach erfassbar und durchsichtig sein. 
Je mehr aus dem Code direkt ersichtlich ist, desto weniger muss 
dokumentiert werden.

Niemand zahlt VHDL Entwickler für schönen und komplexen Code, sei er 
auch noch so elegant. Daher ist es generell unzweckmässig, die Tiefen 
und Breiten dieser Sprache in allen Einzelheiten auszureizen oder dies 
zu versuchen. Preise für elegantes VHDL, die von einer Komission für 
modernes EDA vergeben würden, sind mir nicht bekannt.

Das war jetzt nicht die Anwort auf Deine Frage, aber ich höffe, sie 
hilft Dir trotzdem etwas weiter.

Welche Strategien und Überlegungen werden denn diesbezüglich von den 
Profs so kommuniziert? Gibt es da nur VHDL-Vorlesungen oder auch 
Hinweise, worauf es ankommt? - Täte mich mal so interessieren.

von Bitflüsterer (Gast)


Lesenswert?

Je nach IDE kannst Du Dir eine RTL-Schaltung anzeigen lassen. Das 
ISE-Webpack kann das.

Das gibt dem, der sich mal mit dem Aufbau von Schaltung auf Gatterebene 
beschäftigt hat, eine Vorstellung auf welchem Größen- und 
Komplexitätsebenen er sich bewegt.

von Michael W. (Gast)


Lesenswert?

@Weltbester FPGA-Pongo:

Hallo und danke für die Antwort!

Das Beispiel diente für mich lediglich als Spielwiese für das, was ich 
im Buch lesen durfte. Dass man einen simplen Zähler einfacher abbilden 
kann ist mir bekannt, war aber nicht das Thema. Irgendwo muss man ja 
ausprobieren dürfen, ohne gleich eine hochkomplexe Industrieschaltung zu 
realisieren.

Wieso ist mein Zugang ungewöhnlich bzw. andersrum gefragt, wie müsste er 
sein, um als "normal" zu gelten? Jemand der C lernt wird sich anfangs 
auch ein wenig mit Syntax und Sprachelementen herumspielen, oder? Ich 
habe halt das Buch genommen, und Kapitel für Kapitel durchgenommen samt 
Übungen...wie sonst?

Ich gehe auf keine Uni sondern möchte mir VHDL privat anschauen, da es 
sowas zu meiner Zeit (habe meine Ausbildung in den frühen 80-ern 
abgeschlossen) nicht gab und ich es hochinteressant finde, dass man auf 
diese Weise "Hardware" synthetisieren kann. Damals lernte ich, wie man 
Digitalschaltungen von Hand designte, jetzt ist das scheinbar anders...

Wenn man eine Bildungslücke schließen will, muss man ja nicht gleich in 
dem Gebiet als Profi arbeiten...Dass ich als Hobbyist nicht weit kommen 
werden, ist mir sowieso klar, aber es macht mir halt trotzdem Spaß...

von Klaus F. (kfalser)


Lesenswert?

Michael W. schrieb:
> Damals lernte ich, wie man
> Digitalschaltungen von Hand designte, jetzt ist das scheinbar anders...

Wenn Du von Digitalschaltungen eh schon Ahnung hast, dann besteht ja 
Hoffnung :-)
Ich kann mich erinnern, dass mir VHDL am Anfang auch komplett 
unverständlich und verwirrend war.

Du solltest Dir bewusst sein, dann man mit VHDL das Pferd von hinten 
aufzäunt.
Man beschreibt ein Verhalten, und der Compiler macht dann Hardware 
daraus, das dieses Verhalten zeigt.
Wenn Du das Verhalten kompliziert beschreibst, mit Funktionen und so, 
aber das Verhalten ist immer noch das eines Zählers bis 10, dann kommt 
trotzdem immer ein Hardware Zähler bis 10 heraus.
Wenn Du das Ganze zu kompliziert beschreibts, dann kann es sein, dass 
der Compiler das beschriebene Verhalten nicht mehr versteht, und die 
falsche Hardware generiert. Aus diesem Grund gibt es IEEE Standards und 
Handbüchern zu den Compilern, wo steht, was erlaubt ist.
Lies Dir z.B. einmal den User Guide zum XST oder "Xilinx Synthesis and 
Simulation Design Guide", da steht drinnen, wie man ein FF oder eine FSM 
beschreibt, damit's verstanden wird.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michael W. schrieb:
> count <= increment(count) after tpd_clk_to_count;
Keine symbolischen Delays in einer Hardwarebeschreibung verwenden! Das 
kann böse ins Auge gehen:
Beitrag "Re: Frage zu Pseudozufallsgenerator!?"

Und welche 10% der Syntaxelemente von VHDL tatsächlich in Hardware 
umgesetzt werden können, steht im User Guide des entsprechenden 
Synthesizers...

von 123abc (Gast)


Lesenswert?

Weltbester FPGA-Pongo schrieb im Beitrag #3711820:
> Ohne zu Dir und Deinen Code-Überlegungen im Detail Stellung nehmen
> zu
> wollen, erlaube ich mir die Bemerkung, dass die Art der Annäherung an
> das Thema VHDL sagen wir mal, "ungewöhnlich" ist!

Ich finde deine Antwort an den TO als nicht sehr nett.

Um es hier mal auf den Punkt zu bringen:
1) Der TO will sich in ein neues Thema einarbeiten
2) Er hat sich ein Buch beschafft und dies auch angeschaut, und eine 
Einarbeitung ist meiner Meinung nach ersichtlich.
3) Er hat eine konstrutive Frage gestellt: Ist meine Beschreibung so gut 
und für die Toolchain brauchbar?
4) Er beschreibt schon sehr genau sein Problem: Er kann sich erstmal 
nicht vorstellen, was genau die Toolchain aus seinem Code macht. (Viele 
die hier mit FPGAs arbeiten, habe ich den Eindruck, dass sich diese 
dieser Frage noch bei weitem nicht bewusst sind!)
5) Er hat Code geliefert und fragt nach einer Verbesserung!
6) Und das was viele nach mehrmaligen ermahnen nicht schaffen, der TO 
simuliert seine Schaltung!!!

@ Weltbester FPGA-Pongo: Ich verstehe hier in keinster Weise deine 
Kritik.

@ Michael:
Ich finde deine herangehensweise vorbildlich! Lass dich hier nicht 
unterkriegen. Weiter so!

Ein Tipp von mir:
Du weißt schon, wie man digitale Schaltungen von Hand designed, dann 
weißt du ja auch, wie dein Zähler in etwa als Logik aussehen soll. Die 
Toolchains (Xilinx, Altera etc.) können ein Schematic von deiner 
Implementierung ausgeben. Das könnte dir schonmal weiterhelfen, ob es in 
etwa deiner Vorstellung entspricht.

Tricks, wie man etwas optimiert und bei gleicher Funktion 
resourcenschonender und besser leserlich machen kann lernt man nicht von 
Heute auf Morgen, sondern erst, wenn man viel damit gemacht hat. Man 
bekommt irgendwann ein Gefühl dafür und man fängt einfach an in Logik zu 
denken. z.B. in dieser Zeile "erzeuge" ich so und soviel FlipFlops, Bei 
dieser Abfrage vergleiche ich 64 Signale auf größergleich (=komplizierte 
Logik) -> kann man dies mit einer äquivalenten Abfrage vereinfachen?

Wie Lothar schon sage, die delays dienen eigentlich nur der Simulation 
und können in HW nicht umgesetzt werden.
Meiner Meinung nach solltest du am Anfang auch auf Funktionen und 
Proceduren verzichten. Die verleiten etwas schnell hinzuschreiben, was 
dann aber aus unachtsamkeit viel Logik verursacht.

Kopf hoch und einen schönen Abend noch!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

123abc schrieb:
> Meiner Meinung nach solltest du am Anfang auch auf Funktionen und
> Proceduren verzichten.
"Anfang" bedeutet hier in etwa "das erste (halbe) Jahr"...

Eine Funktion oder eine Prozedur und insbesondere eine Schleife ist in 
VHDL etwas grundlegend Anderes als in einer Programmiersprache. Sowas 
gehört bestenfalls in eine Testbench, aber nicht in die Hardware.

von Christoph Z. (christophz)


Lesenswert?

Meine Antwort bezieht sich hier auf die Synthese, nicht auf Testbenches 
oder reine Simulation.

Michael W. schrieb:
> Als Spielerei (!!) habe ich ein Beispiel so umgebaut, dass die Funktion
> mit unsigned statt bit_vector variablen rechnet. So kann ich bis 10
> Zählen und setze dann den Zähler wieder auf 3. Das ginge auch anders mit
> "00001010" und "00000011" und einem bit_vector.  Wie wirkt sich das nun
> aus? Ich tue mir schwer vorzustellen, wie die Variablen einer Funktion,
> die in einem Prozess verwendet wird umgesetzt werden.

Wie du wohl schon vermutest, kommt die typische Ingenieur Antwort: 
"Kommt drauf an" :-)

Der Synthesizer analysiert die Beschreibung deines Prozesses und 
entscheidet dann mal grundsätzlich, ob der Wert der Variablen immer 
eindeutig bestimmt ist, wenn die Variable verwendet wird um einem Signal 
einen Wert zu zu weisen.

Wenn das nicht der Fall ist, muss der Synthesizer Flip-Flops einbauen, 
um den Variablen Wert zu speichern -> Wenn das so gewünscht ist, 
solltest du besser ein Signal verwenden.

Wenn die Variable immer einen definierten Wert bekommt, unabhängig von 
der Vergangenheit, dann baut der Synthesizer eine kombinatorische 
Schaltung. Du kannst dir in solchen Fällen die Variable als 
"Zwischenergebnis eines kombinatorischen Blocks" vorstellen. -> Hier ist 
es OK eine Variable zu verwenden, wenn die Leserlichkeit erhöht wird.

Eine Funktion die synthetisierbar sein soll, sollte so geschrieben sein, 
dass sie nur Kombinatorik beschreibt. Was in deinem Beispiel auch so 
ist.

> Wie werden z.B. Konvertierungsfunktionen umgesetzt? Als vordefinierte
> Einheit, die dann eingebunden wird?

Auch hier, je nach dem. Vielfach nutzt man werteingeschränkte 
Integerdatentypen für Zähler und um Arrays etc. zu adressieren. Weil es 
für uns besser lesbar ist und oft einfachere Beschreibungen ergibt.
Genau so wie bei einem Mikroprozessor auch, kann der FPGA aber kein 
Dezimalsystem, sondern alle Integer werden als Binärzahlen dargestellt 
und verwendet.
Im Endeffekt ist also die Konvertierung von/nach Integer gratis (schon 
fast wie ein type cast).

Konvertierung nach z. B. real ist ein anderes Thema, das kostet Logik. 
Aber niemand verwedet einen real Datentyp innerhalb eines FPGAs (Neu 
auftauchende Lösungen für High-End FPGAs für High-End Probleme 
ausgenommen).

von Michael W. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe versuchsweise das gleiche Verhalten auf 2 Arten realisiert.

1)
1
--
2
-- Copyright 1991-2010 Mentor Graphics Corporation
3
--
4
-- All Rights Reserved.
5
--
6
-- THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS THE PROPERTY OF 
7
-- MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS SUBJECT TO LICENSE TERMS.
8
--   
9
10
library IEEE;
11
use IEEE.std_logic_1164.all;
12
use IEEE.numeric_std.all;
13
14
entity test1 is
15
  port (count : buffer bit_vector(8 downto 1);
16
    clk   : in bit;
17
    reset : in bit);
18
end;
19
20
architecture only of test1 is
21
22
  function increment(val : bit_vector) return bit_vector
23
  is
24
    -- normalize the indexing
25
    alias input : bit_vector(val'length downto 1) is val;
26
    variable ucount: unsigned(val'length downto 1) := unsigned(To_StdLogicVector(val));
27
  begin
28
    if ucount < 10 then
29
       ucount := ucount + 1;
30
    else
31
       ucount := to_unsigned(3, val'length);
32
    end if;
33
    return To_bitvector(std_logic_vector(ucount));
34
  end increment;
35
begin
36
37
  ctr:
38
  process(clk, reset)
39
  begin
40
    
41
    if reset = '1' then
42
        count <= (others => '0');
43
    elsif clk'event and (clk = '1') then
44
       count <= increment(count);
45
    end if;
46
  end process;
47
48
end only;



2)
1
---
2
-- Copyright 1991-2010 Mentor Graphics Corporation
3
--
4
-- All Rights Reserved.
5
--
6
-- THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS THE PROPERTY OF 
7
-- MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS SUBJECT TO LICENSE TERMS.
8
--   
9
10
entity other is
11
  port (count : buffer bit_vector(8 downto 1);
12
    clk   : in bit;
13
    reset : in bit);
14
end;
15
16
architecture only of other is
17
18
begin
19
20
  process(clk, reset)
21
  variable result : bit_vector(8 downto 1) := count;
22
  variable carry : bit;
23
  begin
24
    if (reset = '1') then
25
        count <= (others => '0');
26
    elsif clk'event and (clk = '1') then
27
      if count = "00001010" then
28
          count <= "00000011";
29
      else
30
         carry := '1';
31
         result := count;
32
         for i in 1 to 8 loop
33
           result(i) := count(i) xor carry;
34
           carry := count(i) and carry;
35
           exit when carry = '0';
36
          end loop;
37
         count <= result;
38
      end if;
39
    end if;
40
  end process;
41
42
end only;

Der Simulator zeigt das gleiche Verhalten.

Nun die Quartus RTL Views:

1) test1
2) other

Obwohl ich bei der ersten Variante unnötige Konvertierungsfunktionen 
verwendete (und auch eine Funktion...) ist das Ergebnis sehr einfach und 
transparent.

Hingegen erscheint mir das Ergebnis im 2. Fall unnötig kompliziert, 
abgesehen davon, dass ich nicht weiß, weshalb Ports erzeugt werden, die 
im Modell nicht definiert sind (.._OUT0). Was hat es damit auf sich und 
was ist nun "besser" ?

Danke für die Geduld mit einem Anfänger ;-)

von Duke Scarring (Gast)


Lesenswert?

Michael W. schrieb:
> Was hat es damit auf sich und
> was ist nun "besser" ?
Ich finde Variante 1 übersichtlicher.

Ich würde aber noch folgende Dinge ändern:

1. Index der Vektoren von (Breite-1 downto 0)
   Dsa ist zwar erstmal ungewohnt, aber gibt weniger Probleme mit Code 
aus dem Netz oder von Kollegen.

2. Statt dem Typ buffer in der Porbeschreibung verwendet man 
üblicherweise ein internes Signal, welches dann dem out Port 
zugewiesen wird.

3. Auf den Datentyp bit würde ich verzichten, zumal Du ja schon die 
(mächtigere) Bibliothek ieee.std_logic_1164 einbindest.

4. Ich würde auf den Reset verzichten, wenn das Design ins FPGA kommen 
soll und der Reset nicht unbedingt benötigt wird. Dazu gibt es unzählige 
Diskussionen hier, daher jeder nach seinem Geschmak...


Bei mir würde der Code daher so aussehen:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
entity test1 is
6
    port (
7
        clk   : in  std_logic;
8
        count : out std_logic_vector(7 downto 0)
9
        );
10
end entity test1;
11
12
architecture only of test1 is
13
14
    signal count_int : unsigned(7 downto 0) := (others => '0');
15
16
    function increment(val : unsigned) return unsigned is
17
        variable ucount : unsigned(val'range) := val;
18
    begin
19
        if ucount < 10 then
20
            ucount := ucount + 1;
21
        else
22
            ucount := to_unsigned(3, val'length);
23
        end if;
24
        return ucount;
25
    end function increment;
26
27
begin
28
29
    process
30
    begin
31
        wait until rising_edge(clk);
32
        count_int <= increment(count_int);
33
    end process;
34
35
    count <= std_logic_vector(count_int);
36
37
end architecture only;

Hier eine passende Testbench:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
4
entity test1_tb is
5
end entity test1_tb;
6
7
architecture testbench of test1_tb is
8
9
    constant clk_period : time := (1 sec) / 100_000_000;
10
11
    signal tb_clk   : std_logic := '0';
12
    signal tb_count : std_logic_vector(7 downto 0);
13
14
begin
15
16
    tb_clk <= not tb_clk after clk_period / 2;
17
18
    dut : entity work.test1
19
        port map (
20
            clk   => tb_clk,            -- : in  std_logic;
21
            count => tb_count           -- : out std_logic_vector(7 downto 0)
22
            );
23
24
end architecture testbench;

Duke

von Christoph Z. (christophz)


Lesenswert?

Michael W. schrieb:
> Obwohl ich bei der ersten Variante unnötige Konvertierungsfunktionen
> verwendete (und auch eine Funktion...) ist das Ergebnis sehr einfach und
> transparent.
>
> Hingegen erscheint mir das Ergebnis im 2. Fall unnötig kompliziert,
> abgesehen davon, dass ich nicht weiß, weshalb Ports erzeugt werden, die
> im Modell nicht definiert sind (.._OUT0). Was hat es damit auf sich und
> was ist nun "besser" ?

Jetzt rein auf die beiden RTL Views bezogen:
Du hast einen einfachen Aufwärtszähler beschrieben. Also erwartest du 
genau sowas wie im Bild "test1"

Das Bild "other" zeigt dir sofort, dass du nicht das bekommen hast, was 
du beschreiben wolltest :-)

Lothar hat ja schon angemerkt:
Lothar Miller schrieb:
> und insbesondere eine Schleife ist in VHDL etwas grundlegend Anderes als
> in einer Programmiersprache

Sowas passiert, wenn der Synthesizer deine for Schleife ausrollt... (Er 
berechnet die ganze Schleife gleichzeitig und parallel!)

von greg (Gast)


Lesenswert?

Lothar Miller schrieb:
> Eine Funktion oder eine Prozedur und insbesondere eine Schleife ist in
> VHDL etwas grundlegend Anderes als in einer Programmiersprache. Sowas
> gehört bestenfalls in eine Testbench, aber nicht in die Hardware.

Tut mir leid, aber so pauschal ist das grober und für Anfänger 
verwirrender Unfug.

Werden Funktionen, Prozeduren und Schleifen anders umgesetzt als in 
einer Programmiersprache? Sicher. Aber wenn einem dies klar ist, kann 
man die auch gut einsetzen. Für Designs, die intensiv Generics nutzen, 
sind Funktionen und Schleifen häufig sogar absolut unerlässlich.

von Punkt Setzer (Gast)


Lesenswert?

greg schrieb:
>> Eine Funktion oder eine Prozedur und insbesondere eine Schleife ist in
>> VHDL etwas grundlegend Anderes als in einer Programmiersprache. Sowas
>> gehört bestenfalls in eine Testbench, aber nicht in die Hardware.
>
> Tut mir leid, aber so pauschal ist das grober und für Anfänger
> verwirrender Unfug.

Lothar meint wohl "selbstgeschriebene" Funktionen und Prozeduren,

rising-edge() oder to_unsigned() etc. aus synthesefähigen libraries sind 
natürlich auch von Anfängern Nebenwirkungsfrei einsetzbar.

Auch aus meiner Sicht ist es sinnvoll und hilfreich VHDL-Anfängern 
Selbstbeschränkungen hinsichtlich verwendeten Code-konstrukten 
anzuraten. Insbesonders wenn man dem Synthese wie der TO selbst einräumt 
wie "Schwarzer magie" gegenübersteht.

Gruß,

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

greg schrieb:
> Für Designs, die intensiv Generics nutzen, sind Funktionen und Schleifen
> häufig sogar absolut unerlässlich.
Genau dafür wird der besagte Anfänger diese Syntaxelemente dann deiner 
Ansicht nach auch täglich brauchen. Oder wie?

Ich bleibe dabei: ein Anfänger sollte sein kleines Design erst mal ohne 
solche Sachen auf der Hardware zum Laufen bringen. Und dann, wenn er 
etwas Erfahrung hat, nachsehen, was man optimieren könnte und den Gewinn 
aus solchen Sachen ziehen.

Aber niemals würde ich jemandem, der die Seitenwirkungen noch nicht 
einschätzen kann, empfehlen, solche Sprachkonstrukte (die ich selber 
ohne mit der Wimper zu zucken verwende) einzusetzen.

Das ist m.E. das Problem bei einem Buch: es sieht wegen der gleichen 
Schrift irgendwie alles "gleichwertig" und "gleich wichtig" aus...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.