Forum: FPGA, VHDL & Co. Was läuft parallel im FPGA? - Verständnisfragen


von M. M. (mrmcchicken)


Lesenswert?

Hallo, ich fange gerade mit VHDL und FPGAs an. Bei meinen ersten 
Versuchen bin ich nun auf ein Problem gestoßen. Alles funktioniert so 
wie es soll, ich bin mir aber nicht sicher warum.
Das Programm (nennt man Synthetisierten VHDL Code so?) soll einen Taster 
entprellen und bei steigender Flanke eine Variable bis 255 hoch zählen 
und den Wert der Variable dann an 8 LEDs ausgeben. (Kompletter Code 
unten)

Was mir Kopfzerbrechen bereitet ist nun die Auswertung der steigenden 
Flanke. Schließlich wird ein vorher Wert mit einem nachher Wert 
verglichen.
Aus der Zeile:
1
if ((sig0 xor sig1) and not sig1) ='1' then
geht für mich hervor, dass sig1 der vorher Wert ist und sig0 der nachher 
Wert. Beim Schreiben des Codes habe ich mir eigentlich gedacht es wäre 
anders herum.

Ich sehe jetzt irgendwie nicht wo der nachher Wert sig0 zugeordnet wird.
Schließlich wird unmittelbar nach der Zuweisung
1
sig1 <= sig0
eine if Abfrage gemacht die beide Signale auf eine steigende Flanke 
untersucht.

Eine andere Sache die ich nicht ganz verstehe ist folgender Fall:
Was passiert wenn der vorher Wert gerade zugewiesen wird während sich 
der nachher Wert ändert.
1
if sysclk'event and sysclk = '1' then
2
sig1 <= sig0;
3
if ((sig0 xor sig1) and not sig1) ='1' then
Bei jeder Steigenden Flanke wird sig0 sig1 zugeordnet. Der Rest läuft 
asynchron ab. Gäbe es hier die Möglichkeit, dass sig0 seinen Zustand 
nochmal ändert bevor die if Abfrage abgearbeitet ist, und ist es 
sicherer hier nochmal sysclk auf eine steigende Flanke zu prüfen und 
nicht nur sig0 und sig1? Meine Befürchtung ist, dass bei einer längeren 
if Abfrage eben dieser Fall eintritt und eine steigende Flanke mit sig1 
und sig0 nicht erkannt werden kann.
------------------------------------------------
Code:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
use ieee.std_logic_unsigned.all;
5
6
7
entity taster is
8
    Port ( taster : in STD_LOGIC;
9
           sysclk : in STD_LOGIC;
10
           led : out STD_LOGIC_VECTOR (7 downto 0));
11
           
12
end taster;
13
14
architecture Behavioral of taster is
15
  
16
  signal sig0 : STD_LOGIC := '0';
17
  signal sig1 : STD_LOGIC := '0';
18
  signal clk0 : integer range 0 to 1999999 := 0;
19
  signal cnt1 : integer range 0 to 10000 := 0;
20
  signal cnt0 : STD_LOGIC_VECTOR (7 downto 0);
21
22
begin
23
24
  prcs0 : process (sysclk)
25
  begin
26
  
27
  if sysclk'event and sysclk = '1' then
28
    if taster = '1' then
29
      if clk0 = 1999999 then
30
        sig0 <= '1';
31
32
      else
33
        clk0 <= clk0 +1;
34
      end if;
35
    else
36
      clk0 <= 0;
37
      sig0 <= '0';
38
    end if;
39
  end if; 
40
41
  end process;
42
  
43
  
44
  count : process (sysclk)
45
  begin
46
  
47
48
  if sysclk'event and sysclk = '1' then
49
  sig1 <= sig0;  
50
  if ((sig0 xor sig1) and not sig1) ='1' then
51
    cnt0 <= cnt0 +1;
52
  else
53
    cnt0 <= cnt0;
54
  end if;
55
  end if;
56
  
57
  end process;
58
 
59
 
60
  led <= cnt0;
61
62
63
end Behavioral;

: Bearbeitet durch User
von Achim S. (Gast)


Lesenswert?

M. M. schrieb:
> Ich sehe jetzt irgendwie nicht wo der nachher Wert sig0 zugeordnet wird.
> Schließlich wird unmittelbar nach der Zuweisungsig1 <= sig0 eine if
> Abfrage gemacht die beide Signale auf eine steigende Flanke
> untersucht.

diese Abfrage bezieht sich aber noch nicht auf den gerade eben 
zugewiesenen Wert von sig1. Zuweisungen an Signale in Prozessen werden 
erst "am Ende des Prozesses" wirksam. Während aller Abfragen innerhalb 
des Prozesses hat Sig1 noch den "vorherigen" Wert.

Konkret in Hardware umgesetzt bedeutet das:
du generierst ein Flip-Flop für Sig1. Bei jeder steigenden Taktflanke 
übernimmt das Flip-Flop seinen Eingangswert
Abfragen von Sig1 beziehen sich auf den Ausgang des FlipFlops, der bei 
der letzten Taktflanke gesetzt wurde.
Zuweisungen an Sig1 legen den Eingang des FipFlops fest, der bei der 
steigenden Taktflanke als Ausgang übernommen wird.

Um die Abfolge erst mal besser zu verstehen gibt es die sog. 
Zwei-Prozess-Schreibweise (insbesondere für State-Machines), bei der 
Eingang und Ausgang des FlipFlops als getrennte Signale betrachtet 
werden. Wenn man es dann aber mal verinnerlicht hat, dann nerven der 
Zusatzaufwand und die Fallstricke der Zwei-Prozess-Schreibweise (geht 
zumindest mir so), und man schreibt stattdessen die Zuweisung ans 
FlipFlop in einem Prozess (so wie in deinem Beispiel).

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


Lesenswert?

Achim S. schrieb:
> Zuweisungen an Signale in Prozessen werden erst "am Ende des Prozesses"
> wirksam.
Das führt zu dem für Software-Programmierer seltsam verwirrenden Effekt, 
dass die Reihenfolge der Abfrage eines Signals und die Zuweisung von 
Werten an ein Signal in beliebiger Reihenfolge im Prozess stehen können.

Diese beiden Beschreibungen ergeben das selbe Resultat:
1
  count : process (clk)
2
  begin
3
    if rising_edge(clk) then
4
      cnt <= cnt+1;       ---------  
5
      if cnt = 55 then
6
        y <= 1;
7
      else
8
        y <= 0;
9
      end if;
10
    end if;
11
  end process;
Ergibt genau das Selbe:
1
  count : process (clk)
2
  begin
3
    if rising_edge(clk) then
4
      if cnt = 55 then
5
        y <= 1;
6
      else
7
        y <= 0;
8
      end if;
9
      cnt <= cnt+1;      ----------
10
    end if;
11
  end process;
Denn während des Prozesses wird mit dem "alten" Wert von cnt gerechnet. 
Erst am Prozessende wird der neue Wert zugewiesen.

M. M. schrieb:
> Was läuft parallel im FPGA? - Verständnisfragen
Mein wirchtigster Tipp: sieh dir den RTL-Schaltplan des Synthesizers an. 
Dann siehst du nämlich genaz genau, wie deine Beschreibung in Hardware 
umgesetzt wurde...

> use ieee.std_logic_unsigned.all;
Lies den Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete"
Und nimm fürderhin die numeric_std:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std

von Michael W. (Gast)


Lesenswert?

Ein philosophischer Ansatz: "Ist nicht alles in einem FPGA parallel"?

Ein Tipp:

Das hier " if ((sig0 xor sig1) and not sig1) ='1' then" ist viel zu 
abstrakt formuliert.

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


Lesenswert?

Markus W. schrieb:
> viel zu abstrakt formuliert.
Ich nehme da immer gleich ein Schieberegister bestehend aus einem kurzen 
Vektor:
http://www.lothar-miller.de/s9y/categories/18-Flankenerkennung

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

M. M. schrieb:
>
1
if ((sig0 xor sig1) and not sig1) ='1' then

Das ist identisch mit:
1
if (sig0 = '1') then

von Bit Wurschtler (Gast)


Lesenswert?

Andreas S. schrieb:
> M. M. schrieb:
>>if ((sig0 xor sig1) and not sig1) ='1' then
> Das ist identisch mit:if (sig0 = '1') then

Nein, check mal den Fall sig1 = '1'.

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


Lesenswert?

Bit Wurschtler schrieb:
> Nein
Kann auch nicht sein, denn eine XOR bedeutet "ungleich", und dafür 
müssen beide Bits wirken können.

Ergo steht da:
1
if ((sig0 xor sig1)                                  and not sig1) ='1' then
2
-->
3
if ((sig0='0' and sig1='1' or sig0='1' and sig1='0') and sig1='0' then
4
--> 
5
if ((sig0='0' and sig1='1' and sig1='0') or (sig0='1' and sig1='0' and sig1='0')) then
6
-->
7
if (                                        (sig0='1' and sig1='0'              ) then
Und weil sig0 der "aktuelle" Zustand und sig1 der "alte" Zustand ist, 
wird damit auf eine steigende Flanke abgefragt...

: Bearbeitet durch Moderator
von M. M. (mrmcchicken)


Lesenswert?

Lothar M. schrieb:
> Achim S. schrieb:
>> Zuweisungen an Signale in Prozessen werden erst "am Ende des Prozesses"
>> wirksam.
> Das führt zu dem für Software-Programmierer seltsam verwirrenden Effekt,
> dass die Reihenfolge der Abfrage eines Signals und die Zuweisung von
> Werten an ein Signal in beliebiger Reihenfolge im Prozess stehen können.
>
> Diese beiden Beschreibungen ergeben das selbe Resultat:

Dass Signale immer erst am Ende eines Prozesses zugewiesen werden ist 
mir bekannt, ich versuche es immer im Hinterkopf zu behalten aber es ist 
doch schwierig aus der Zeile-für-Zeile Denkweise herauszukommen wenn man 
so lange mit Mikrocontrollern vorher zu tun hatte.
Nun scheint es mir, dass ich begriffen habe wie das ganze abläuft.
Wenn der Taster nicht gedrückt wird, haben bei Signale den Wert 0.
Nun wird der Taster gedrückt und in dem Takt danach wird dem Signal0 der 
Wert 1 zugeschrieben, Signal1 behält seinen aktuellen Wert. Außerdem 
werden beide Signale in diesem Takt auf eine steigende Flanke untersucht 
und dann auch erkannt.
Im nächsten Takt haben beide Signale den Wert 1 und nichts passiert.

Gibt es zur RTL Analyse ein Dokument welche die Blöcke erklärt? Die 
meisten sind mir zwar bekannt aber es wäre auch schön nochmal nach 
gucken zu können.

Danke soweit für die Hilfe, die andere Lib werde ich mir mal anschauen.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Bit Wurschtler schrieb:
> Nein, check mal den Fall sig1 = '1'.

Oh, wie peinlich... :-(

von Lattice User (Gast)


Lesenswert?

M. M. schrieb:
> Wenn der Taster nicht gedrückt wird, haben bei Signale den Wert 0.
> Nun wird der Taster gedrückt und in dem Takt danach wird dem Signal0 der
> Wert 1 zugeschrieben, Signal1 behält seinen aktuellen Wert.

Nein, sig1 bekommt immer den alten Wert von sig0. sigt1 ist damit nichts 
anderes als eine um einen Takt verzögerte Kopie von sig0

> Außerdem
> werden beide Signale in diesem Takt auf eine steigende Flanke untersucht
> und dann auch erkannt.

Der FPGA untersucht nichts auf Flanke, sondern das steht in deiner 
Beschreibung. Deine orginale Variante ist da schwer zu durchschauen, 
in Lothars verreinfachter Form ist es offensichtlich wie es 
funktioniert,
1
if ( sig0='1' and sig1='0' ) then

esultat:
>
> Dass Signale immer erst am Ende eines Prozesses zugewiesen werden ist
> mir bekannt, ich versuche es immer im Hinterkopf zu behalten aber es ist
> doch schwierig aus der Zeile-für-Zeile Denkweise herauszukommen wenn man
> so lange mit Mikrocontrollern vorher zu tun hatte.


Einfache Betrachtungsweise:
Was rechts von einer Zuweisung steht ist der Zustand vor der 
Taktflanke, die Zuweisung bestimmt was bei der Flanke passieren soll, 
und damit den Zustand nach der Taktflanke.

Wenn ein Signal mehrfach auf der linken Seite einer Zuweisung vorkommt, 
gilt die letzte im Prozess, eventuell in Abhängigkeit von Bedingungen.

Kombinatorische Prozesse sind etwas komplexer, da bei korrekter 
Sensititvitylist der Prozess gleich noch mal zum Tragen kommt, wenn sich 
ein Signal ändert, das sowohl auf der rechten als auf der linken Seite 
einer Zuweisung steht. Das ist fast immer unerwünscht (Kombinatorische 
Schleife) also unbedingt vermeiden.
Auch sollte man im kombinatorischen Prozess darauf achten, dass ein 
Signal unter allen Bedingungen zugeweisen wird, sond kassiert man 
unerwünschte Latches. Kann man damit sicherstellen, dass man am Anfang 
Defaultzuweisungen hinschreibt, und erst danach bedingte Zuweisungen.

von M. M. (mrmcchicken)


Lesenswert?

Lattice User schrieb:
> Nein, sig1 bekommt immer den alten Wert von sig0. sigt1 ist damit nichts
> anderes als eine um einen Takt verzögerte Kopie von sig0

Da habe ich mich wohl  ungeschickt ausgedrückt, das habe ich nämlich 
damit sagen wollen.

Lattice User schrieb:
> Der FPGA untersucht nichts auf Flanke, sondern das steht in deiner
> Beschreibung. Deine orginale Variante ist da schwer zu durchschauen,
> in Lothars verreinfachter Form ist es offensichtlich wie es
> funktioniert,
1
if ( sig0='1' and sig1='0' ) then

Nun verstehe ich genau wie das gemeint ist. Tatsächlich so ist es immens 
einfacher.

Danke euch allen, ihr habt mir sehr weiter geholfen!

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.