Forum: FPGA, VHDL & Co. Frage zu Schaltverhalten innerhalb einer State Machine (Testbench)


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Christian W. (christian_w79)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe mit meiner Testbench ein Problem. Im Status Z0 wird der Zustand 
von ENABLE nicht erkannt. ENABLE bleibt auf LVDS[2] LOW, vermutlich weil 
es kurz vor der Schaltflanke auch LOW war.

Der Übergang von z0 zu z1 wird allerdings erkannt, clk_display war aber 
auch vor der Schaltflanke 0. Warum wird das unterschiedlich gehandhabt?

Zum Hintergrund: Ich habe mir eine Testbench für ein Video-Framework 
geschrieben. Diese Signale (VSYNC, HSYNC, ENABLE sowie Rot, Grün und 
Blau a 6 Bit) möchte ich nun per SPWG-Mapping in einen LVDS-Takt und 
drei LVDS-DATA-Leitungen packen.
1
pEINPACKER_UEBERGANG: process
2
begin
3
  wait until rising_edge(clk_fast);
4
  case zustand is
5
    when z0 =>  if(clk_display = '1') then
6
            zustand <= z1;
7
            -- Ausgänge für Z1
8
            lvds_clk <= '1';    -- Ausgeben
9
            lvds_data(2) <= enable;  -- HIER IST DAS PROBLEM! Wenn ich hier '1' eingebe funktioniert es: Das LVDS-Bit wird gesetzt.
10
          end if;
11
    when z1 =>   zustand <= z2;  -- Anfangszustand
12
          -- Ausgänge für Z2
13
          lvds_clk <= '1';
14
          lvds_data(2) <= vsync;
15
    when z2 =>   zustand <= z3;
16
          -- Ausgänge für Z3
17
          lvds_clk <= '0';
18
          lvds_data(2) <= hsync;
19
    when z3 =>   zustand <= z4;
20
          -- Ausgänge für Z4
21
          lvds_clk <= '0';
22
          lvds_data(2) <= 'X';
23
    when z4 =>   zustand <= z5;
24
          -- Ausgänge für Z5
25
          lvds_clk <= '0';
26
          lvds_data(2) <= 'X';
27
    when z5 =>   zustand <= z6;
28
          -- Ausgänge für Z6
29
          lvds_clk <= '1';
30
          lvds_data(2) <= 'X';
31
    when z6 =>   zustand <= z0;
32
          -- Ausgänge für Z0
33
          lvds_clk <= '1';
34
          lvds_data(2) <= 'X';
35
  end case;
36
end process pEINPACKER_UEBERGANG;

clk_display ist der Displaytakt. clk_fast ist 7x so schnell wie 
clk_display und wird zum Einpacken benutzt.

Christian

von Pat A. (patamat)


Lesenswert?

Wo kommen die Takte 'clk_fast' und 'clk_display' her bzw. wie werden die 
generiert?

Es scheint mir ein Delta-t-Problem mit den Takten zu sein, da sich der 
Zustand von 'z0' nach 'z1' eigentlich erst einen Takt später ändern 
sollte. Zumindest wäre das in Hardware so.

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Eines vorneweg: warum ist enable durch die Bank rot? Was machst du mit 
diesem Signal?

Christian W. schrieb:
> -- HIER IST DAS PROBLEM!
Herzlichen Glückwunsch, du hast die "Latency" entdeckt!

Das Timingverhalten der Simulation ist genau so wie es zu erwarten ist: 
wegen des Taktes ändert sich enable. Und deshalb kann erst mit der 
nächsten Taktflanke auf diese Änderung reagiert werden. Vor der 
weißen Linie ist enable offenbar '0'. Diese '0' wird dann mit der 
Taktflanke, die auch den Zustand wechselt, ins lvds_data(2) Flipflop 
übernommen. einen Takt später ist vor der Taktflanke enable '1' und es 
wird mit dieser Taktflanke diese '1' ins lvds_data(2) Flipflop 
gespeichert. Passt also (abgesehen von den vielen roten Stellen im 
Timingdiagramm) alles.

Andersrum: im Zustand z0 wird alles für den Zustand z1 vorbereitet, 
und im z1 für z2 usw.
Du schreibst es selber, dass im Zustand z6 die Ausgänge des Zustands z0 
gesetzt werden:
1
when z6 =>   zustand <= z0;
2
          -- Ausgänge für Z0
und lvds_data(2) ist ein solcher Ausgang. Dort steht also klar: im 
Zustand z0 möchte ich gerne einen "Kollisions-Pegel" auf lvds_data(2) 
sehen.
Dass daraus letztlich eine '0' wird, steht auf einem anderen Blatt, denn 
sowas ist zwar für die Simulation hübsch, bringt dich aber in der 
Realität nicht weiter:
1
lvds_data(2) <= 'X';
Im FPGA gibt es kein 'X', sondern ausschließlich '0' und '1' und 
bestenfalls noch 'Z'. Diese Geschichte mit 'X' kann dann zu eigenartigen 
Effekten führen. Du solltest auch in der Simulation die Beschreibung 
deiner Hardware mit solchen Pegeln machen, die tatsächlich in dieser 
Hardware auftreten.

Ein Nachtrag: die Geschichte mit dem unterschiedlichen "Erkanntwerden" 
des Signals enable und des clk_display in Relation zum clk_fast findet 
sich ausserhalb des geposteten Codes. Wie werden die beiden Takte 
clk_fast und clk_display erzeugt? In unabhängigen Prozessen? Worauf sind 
die sensitiv, wie werden die angestoßen?

: Bearbeitet durch Moderator
von Christian W. (christian_w79)


Angehängte Dateien:

Lesenswert?

@Pat A Mat
1
constant clk_display_time : time := 42.938 ns;          -- This is the LVDS_CLOCK.
2
constant clk_fast_time : time := clk_display_time / 7;      -- I assume that the LVDS_DATA is 7 times slower than the LVDS_CLOCK.
3
4
-- LVDS Videoclock
5
pCLK_DISPLAY : process
6
begin
7
  clk_display <= '0';
8
  wait for clk_display_time/2;
9
  clk_display <= '1';
10
  wait for clk_display_time/2;
11
end process pCLK_DISPLAY;
12
13
-- Fast 7x Wrapper-Clock
14
pCLK_FAST : process
15
begin
16
  clk_fast <= '0';
17
  wait for clk_fast_time/2;
18
  clk_fast <= '1';
19
  wait for clk_fast_time/2;
20
end process pCLK_FAST;

@Lothar Miller

Die ENABLE-Leitung habe ich im ISIM rot eingefärbt.

Danke für Deine Ausführungen. Ich versuchs mal zusammenzufassen, ob ich 
es richtig verstanden habe:

Im Falle von ENABLE braucht es zwei Takte, bis der Pegel durch 
synthetisierte Elemente an meinem Ausgang lvds_data[2] sichtbar ist.

Im Falle vom Statusübergang von z0 zu z1 dauert dieser Übergang 
allerdings nur einen Takt.

Dies unterschiedliche Bearbeitungszeit muss ich nun irgendwie 
ausgleichen.

Was vielleicht nicht so rausgekommen ist: Auf lvds_data[2] soll nicht 
permanent ENABLE zu sehen sein.

- Im Zustand z1 soll dort ENABLE sein.
- Im Zustand z2 soll dort VSYNC sein.
- Im zustand z3 soll dort HSYNC sein.

VSYNC und HSYNC werden auch ohne Probleme übernommen.

Die Xe ersetze ich in der fertigen Testbench durch 0 und 1. Hier soll es 
nur mal ein Minimalbeispiel sein.

Christian

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Zwei Anmerkungen vorneweg:
1. der LVDS-Takt ist üblicherweise asymmetrisch 3:4

2. deine beiden "Takte" werden mit der Zeit auseinanderlaufen, weil die 
Berechnung nicht vollkommen genau ist:
clk_display_time ist nicht das Gleiche wie (clk_display_time / 7) * 7

Wenn du zeitlich korrelierende Takte brauchst, weil sich deine Design 
darauf verlässt (und das tut es!!), dann musst du die Takte auseiander 
"ableiten". Im FPGA nimmt man dafür einen Taktmanager, du nimmst für die 
Simulation einfach den schnellen Takt und leitest daraus den langsamen 
ab (diese Strategie taugt aber wie gesagt nur für die Simulation):
1
constant clk_display_time : time := 42.938 ns;          
2
constant clk_fast_time : time := clk_display_time / 7; 
3
signal clk_cnt : integer ragne 0 to 6 := 0;
4
5
-- LVDS Videoclock
6
pCLK_DISPLAY : process
7
begin
8
  clk_display <= '0';
9
  wait until rising_clk(clk_fast);
10
  clk_display <= '0';
11
  wait until rising_clk(clk_fast);
12
  clk_display <= '0';
13
  wait until rising_clk(clk_fast);
14
  clk_display <= '1';
15
  wait until rising_clk(clk_fast);
16
  clk_display <= '1';
17
  wait until rising_clk(clk_fast);
18
  clk_display <= '1';
19
  wait until rising_clk(clk_fast);
20
  clk_display <= '1';
21
  wait until rising_clk(clk_fast);
22
end process pCLK_DISPLAY;
23
24
-- Fast 7x Wrapper-Clock
25
pCLK_FAST : process
26
begin
27
  clk_fast <= '0';
28
  wait for clk_fast_time/2;
29
  clk_fast <= '1';
30
  wait for clk_fast_time/2;
31
end process pCLK_FAST;
32
33
-- Oder kürzer ohne Prozess (aber bitte mit Initwert für clk_fast):
34
clk_fast <= not clk_fast after clk_fast_time/2;


Christian W. schrieb:
> VSYNC und HSYNC werden auch ohne Probleme übernommen.
Die sind ja auch schon im Takt vorher (bzw sogar statisch) '1'...

> Im Falle von ENABLE braucht es zwei Takte
Denke nicht in Takten, denke in Flipflops: dein lvds_data(2) ist ein 
D-Flipflop, das mit der Taktflanke den Pegel übernimmt, der an seinem 
D-Eingang vor dieser Taktflanke anliegt. Dadurch ändert sich dann der 
Ausgang.
Auch die z0..z6 sind solche D-Flipflops, die einen Zustand ausgeben, aus 
dem mit einer Kombinatorik dann der nächste Zustand berechnet wird, der 
dann mit der nächsten Taktflanke übernommen und wieder am Ausgang 
ausgegeben wird.

: Bearbeitet durch Moderator
von Christian W. (christian_w79)


Angehängte Dateien:

Lesenswert?

Genau das wars ;))

Nachdem ich den schnellen Takt über TIME bestimmt habe und den 
langsameren über einen Teiler erstellt habe, genau wie Du es 
vorgeschlagen hast, funktioniert alles.

Danke.

Christian

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]
  • [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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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