mikrocontroller.net

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


Autor: Christian W. (christian_w79)
Datum:
Angehängte Dateien:

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

pEINPACKER_UEBERGANG: process
begin
  wait until rising_edge(clk_fast);
  case zustand is
    when z0 =>  if(clk_display = '1') then
            zustand <= z1;
            -- Ausgänge für Z1
            lvds_clk <= '1';    -- Ausgeben
            lvds_data(2) <= enable;  -- HIER IST DAS PROBLEM! Wenn ich hier '1' eingebe funktioniert es: Das LVDS-Bit wird gesetzt.
          end if;
    when z1 =>   zustand <= z2;  -- Anfangszustand
          -- Ausgänge für Z2
          lvds_clk <= '1';
          lvds_data(2) <= vsync;
    when z2 =>   zustand <= z3;
          -- Ausgänge für Z3
          lvds_clk <= '0';
          lvds_data(2) <= hsync;
    when z3 =>   zustand <= z4;
          -- Ausgänge für Z4
          lvds_clk <= '0';
          lvds_data(2) <= 'X';
    when z4 =>   zustand <= z5;
          -- Ausgänge für Z5
          lvds_clk <= '0';
          lvds_data(2) <= 'X';
    when z5 =>   zustand <= z6;
          -- Ausgänge für Z6
          lvds_clk <= '1';
          lvds_data(2) <= 'X';
    when z6 =>   zustand <= z0;
          -- Ausgänge für Z0
          lvds_clk <= '1';
          lvds_data(2) <= 'X';
  end case;
end process pEINPACKER_UEBERGANG;

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

Christian

Autor: Pat A. (patamat)
Datum:

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

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht 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:
when z6 =>   zustand <= z0;
          -- 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:
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
Autor: Christian W. (christian_w79)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@Pat A Mat

constant clk_display_time : time := 42.938 ns;          -- This is the LVDS_CLOCK.
constant clk_fast_time : time := clk_display_time / 7;      -- I assume that the LVDS_DATA is 7 times slower than the LVDS_CLOCK.

-- LVDS Videoclock
pCLK_DISPLAY : process
begin
  clk_display <= '0';
  wait for clk_display_time/2;
  clk_display <= '1';
  wait for clk_display_time/2;
end process pCLK_DISPLAY;

-- Fast 7x Wrapper-Clock
pCLK_FAST : process
begin
  clk_fast <= '0';
  wait for clk_fast_time/2;
  clk_fast <= '1';
  wait for clk_fast_time/2;
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

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht 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):
constant clk_display_time : time := 42.938 ns;          
constant clk_fast_time : time := clk_display_time / 7; 
signal clk_cnt : integer ragne 0 to 6 := 0;

-- LVDS Videoclock
pCLK_DISPLAY : process
begin
  clk_display <= '0';
  wait until rising_clk(clk_fast);
  clk_display <= '0';
  wait until rising_clk(clk_fast);
  clk_display <= '0';
  wait until rising_clk(clk_fast);
  clk_display <= '1';
  wait until rising_clk(clk_fast);
  clk_display <= '1';
  wait until rising_clk(clk_fast);
  clk_display <= '1';
  wait until rising_clk(clk_fast);
  clk_display <= '1';
  wait until rising_clk(clk_fast);
end process pCLK_DISPLAY;

-- Fast 7x Wrapper-Clock
pCLK_FAST : process
begin
  clk_fast <= '0';
  wait for clk_fast_time/2;
  clk_fast <= '1';
  wait for clk_fast_time/2;
end process pCLK_FAST;

-- Oder kürzer ohne Prozess (aber bitte mit Initwert für clk_fast):
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
Autor: Christian W. (christian_w79)
Datum:
Angehängte Dateien:

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