mikrocontroller.net

Forum: FPGA, VHDL & Co. Beschreibung funktioniert nach Synthese nicht


Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

in den folgenden zwei Beispielen lasse ich mir ein Byte ("ToggleByte") 
permanent invertieren und an eine Senderoutine schicken. Beide sind 
einwandfrei simulierbar und tuen, für was sie gedacht. Nach der Synthese 
sieht das anders aus: Das erste Beispiel funktioniert, das zweite nicht.

Hier die beiden Beispiele:

Beispiel 1:
  Debug_Adder : process(CLK)
    variable StateMachine: integer range 0 to 2 := 0;
    variable ToggleByte : STD_LOGIC_VECTOR(7 downto 0) := x"00";
  begin
    if rising_edge(CLK) then

      case StateMachine is
      
      -- Senden
      when 1 =>
        if NewTransmitACK = '0' then                  -- Ist der Sender frei?
          Transmit <= (others => '0');                -- Nachricht pauschal löschen
          Transmit(7 downto 0) <= ToggleByte;         -- Byte zur Überprüfung, ob Nachricht aktualisiert wurde, in Byte 0 senden
          NewTransmit <= '1';                         -- Senden anfordern
        end if;                                       --

      -- Toggeln
      when 2 =>
        if NewTransmitACK = '1' then                  -- Nachricht übernommen?
          NewTransmit <= '0';                         -- Anforderung zurücknehmen
          ToggleByte := not ToggleByte;               -- Byte toggeln
          StateMachine := 0;                          -- StateMachine resetten, um Überlauf zu verhindern
        end if;                                       --
      
      when others =>
        null;
      end case;
      
      StateMachine := StateMachine + 1;                -- Automatisch nächsten Schritt wählen
      
    end if;
  end process;

Beispiel 2:
  Debug_Direct : process(CLK)
    variable StateMachine: integer range 0 to 1 := 0;
    variable ToggleByte : STD_LOGIC_VECTOR(7 downto 0) := x"00";
  begin
    if rising_edge(CLK) then

      case StateMachine is
      
      -- Senden
      when 0 =>
        if NewTransmitACK = '0' then                  -- Ist der Sender frei?
          Transmit <= (others => '0');                -- Nachricht pauschal löschen
          Transmit(7 downto 0) <= ToggleByte;         -- Byte zur Überprüfung, ob Nachricht aktualisiert wurde, in Byte 0 senden
          NewTransmit <= '1';                         -- Senden anfordern
          StateMachine := 1;                          -- Im nächsten Schritt Zähler erhöhen
        end if;                                       --

      -- Toggeln
      when 1 =>
        if NewTransmitACK = '1' then                  -- Nachricht übernommen?
          NewTransmit <= '0';                         -- Anforderung zurücknehmen
          ToggleByte := not ToggleByte;               -- Byte toggeln
          StateMachine := 0;                          -- Im nächsten Schritt wieder das Senden anfordern
        end if;                                       --
      
      end case;
      
    end if;
  end process;


Das meiste davon ist Overhead zum Senden. Der wesentliche Unterschied 
zwischen den beiden Beispielen: Im Ersten gebe ich den nächsten State 
meiner Statemachine im aktuellen State vor, im Zweiten erhöhe ich ihn 
automatisch per Addition. Den Überlauf fange ich dann im letzten Schritt 
der StateMachine ab.


Warum funktioniert das erste Beispiel nicht? Warum dafür das Zweite? Wo 
ist denn nur der Unterschied? Er synthetisiert es anders. Aber was ist 
denn an der ersten Beschreibung nur falsch?

Autor: Frank Buss (foobar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Unterschied ist, daß du im ersten Beispiel die Statemachine-Variable 
unbedingt erhöhst und im zweiten Beispiel nur innerhalb des States. 
Daher würde ich mal vermuten, daß das erste Beispiel nicht läuft. Ist 
sowieso keine gute Idee, das so zu schreiben, da z.B. manche Simulatoren 
einen Overflow-Error ausgeben würden und ich bin mir nicht sicher, ob 
das in VHDL definiert ist, daß es ein Wraparound geben muß bei 
interger-Variablen. Ich mache das immer so, daß ich Überläufe abfange 
bzw. so wie du im zweiten Beispiel, daß die gar nicht erst auftreten 
können.

Noch zwei Tipps: Verwende besser sowas wie "type STATE_TYPE is 
(aussagekraefteriger_name, nochwas);" für die Codierung von 
Statemachines. Für binäre Statemachinen kannst du aber auch eine 
Variable vom Typ "boolean" nehmen. Und "variable" brauchst du an der 
Stelle nicht, nimm besser ein "signal" und dann den becomes-Operator 
("<="). Zu beachten dabei: signale haben während des gesamten Prozesses 
den Wert bei Eintritt des Prozesses, unabhängig davon, was du denen im 
Laufe des Prozesses zuweist und der letzte zugewiesene Wert wird bei 
Verlassen des Prozesses übernommen. Ist nicht schwierig, wenn man sich 
mal dran gewöhnt hat, kann aber manchmal ein paar Gatter sparen 
gegenüber der Programmierung per variable.

Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo foobar,

Frank Buss schrieb:
> Der Unterschied ist, daß du im ersten Beispiel die Statemachine-Variable
> unbedingt erhöhst und im zweiten Beispiel nur innerhalb des States.
> Daher würde ich mal vermuten, daß das erste Beispiel nicht läuft.

Es ist aber genau umgekehrt: Das erste Beispiel funktioniert, das zweite 
nicht. Ich kann aber auch nicht erkennen, was daran falsch sein soll. Im 
nicht-funktionierenden Beispiel wird die Variable nur innerhalb des 
States erhöht - aber was ist daran denn schlimm? Wieso kann er sie nicht 
einfach abspeichern und beim nächsten Durchlauf wieder aufrufen?! Welche 
Regel wird da denn verletzt?

Frank Buss schrieb:
> Noch zwei Tipps [...]

Vielen Dank für Deine Tipps. Ich beherzige sie normalerweise. Für dieses 
Posting habe ich aber allen Ballast rausgeworfen (type). Und die 
Variablen habe ich verwendet, weil ich sie innerhalb des Prozesses 
benennen kann (finde ich für das Verständnis kompakter). Mit Signalen 
ändert sich das Verhalten leider nicht.



Grüße
Steffen

Autor: Frank Buss (foobar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Woher kommt "NewTransmitACK"? Am besten mit rising_edge(CLK) in ein 
zusätzliches "signal" Latch übernehmen und dann dieses verwenden, falls 
die dadurch verursachte Verzögerung von einem zusätzlichen Takt erlaubt 
ist. Asynchron änderbare Signale verursachen schöne Probleme mit 
Setup/Hold-Zeitverletzungen und können zu nicht-determinitischen 
Verhalten führen.

Hatte ich mal bei einer Statemachine gehabt: die blieb nach einiger Zeit 
einfach in irgendeinem illegalen Zustand hängen.

Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank Buss schrieb:
> Woher kommt "NewTransmitACK"?

Das Signal wird intern erzeugt und ist synchron. Du könntest aber 
trotzdem auf der richtigen Spur sein. Es kann an "NewTransmitACK" 
liegen, denn das ist in Beispiel 2 eine Stelle, an der er sich aufhängen 
kann, während in Beispiel 1 dort weitergezählt wird (da externer 
Zähler).

Wenn das stimmt, war ich die ganze Zeit auf dem falschen Dampfer!!

Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, es stimmt leider. Das Signal "NewTransmitACK" war Schuld! Und ich 
habe mir hier einen Wolf gesucht :-((

Vielen Dank für Deinen Hinweis, er hat mir sehr weitergeholfen!

Grüße
Steffen

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.
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.