Wann sollten Zustandsmaschinen verwendet werden - FPGA

Ich habe viel über FSMs (Finite State Machines) gelesen, als ich VHDL-Tutorials gemacht habe. Sie sind einfach und ich habe sie oft benutzt, aber ich verstehe immer noch etwas nicht und kann die Antwort online nicht finden:

Wann sollte ich FSMs (Moore oder Mealy) in meinem VHDL-Design verwenden?

Wenn ich beispielsweise einen Algorithmus (zuvor in C-Sprache) in VHDL implementiere, soll ich dann einen FSM verwenden?

Wenn ein Algorithmus als FSM einer akzeptablen Größe beschreibbar ist, verwenden Sie FSM, da es sich um eine äußerst anschauliche, einheitliche und leicht analysierbare Darstellung handelt. Übrigens verwende ich FSMs auch häufig in C.
Verwenden Sie sie, wenn Sie Zustände berücksichtigen müssen. Der größte Teil meines Python-Codes verwendet FSM, da es eine schöne, prägnante Möglichkeit ist, zu erfassen, was wann passiert
Sie sind der sinnvollste Weg, um den Kontrollfluss für Operationen mit mehreren Zyklen durchzuführen.

Antworten (4)

Wenn Sie eine Operation auf mehrere Taktzyklen aufteilen müssen, haben Sie zwei Möglichkeiten: Pipelining und Sequenzierung

Betrachten wir zum Beispiel eine mythische Operation, die aus vier Multiplikationen besteht - wobei jede Multiplikation (mit Ausnahme der ersten) die Ausgabe der vorherigen Multiplikation als eine ihrer Eingaben benötigt. Die Grundideen sind jedoch viel allgemeiner.

Beim Pipelining haben Sie genügend Hardware, um alle Operationen gleichzeitig auszuführen, die durch Pipeline-Register miteinander verbunden sind. Dies impliziert vier Multiplikatoren, die durch Pipeline-Register getrennt sind. Es dauert 4 Taktzyklen, um das erste Ergebnis zu erhalten (wir sagen also, die Pipeline ist 4 Stufen tief und die Latenz beträgt 4 Zyklen), aber dann erhalten Sie bei jedem Taktzyklus ein neues Ergebnis (also sagen wir, die Durchsatzrate beträgt 1 Zyklus). . Ein paar mehr Informationen zum Pipeline-Design ...

Nachteil: Dies ist ein großes Stück Hardware - 4 Multiplikatoren sind relativ teuer (weshalb einige FPGA-Familien viele kleine Multiplikatoren als hochoptimierte Blöcke anbieten).

Die Alternative besteht darin, jede Operation in demselben Multiplikator zu sequenzieren, was ein viel kleineres Design ergibt, aber alle 4 Zyklen ein Ergebnis liefert.

In diesem Fall können Sie für ein viel kleineres Design einen einzigen Multiplikator verwenden, der sein Ergebnis in einem einzigen Register speichert.

Bei jedem 4. Zyklus (oder immer wenn etwas anderes einen neuen Eingang bereit signalisiert) verbinden Sie den neuen Eingang mit einem Eingangsport des Multiplikators; in anderen Zyklen füttern Sie diesen Port aus dem Ausgangsregister (um das vorherige Multiplikationsergebnis zu verwenden). Und in jedem Zyklus geben Sie die entsprechenden Daten (Filterkoeffizienten, Matrixwerte, was auch immer) in den anderen Multiplikatorport ein. Vier Zyklen später präsentieren Sie das Endergebnis als Ausgabe und signalisieren Ihrem Verbraucher, dass ein neues Ergebnis fertig ist.

Der offensichtliche Weg, diese Operationen zu sequenzieren, ist eine Zustandsmaschine (FSM).

Tatsächlich können die Berechnungen in die Aktionen eingebettet werden, die jedem Zustand zugeordnet sind, zum Beispiel:

if rising_edge(clk) then
   Done <= '0';   -- and any other default actions
   case state is
   when Idle =>
      if Start = '1' then
         Temp  := Input * C1;
         State := S1;
      end if;
   when s1 =>
      Temp  := Temp * C2;
      State := S2;
   when s2 =>
      Temp  := Temp * C3;
      State := S3;
   when s3 =>
      Temp  := Temp * C4;
      State := S4;
   when s4 =>
      Output <= Temp;
      Done   <= '1';
      State  := Idle;
      -- optional alternative for bombproof handshaking
      -- if Start = '0' then
      --    Done <= '1';
      --    State <= Idle;
      -- end if;
   end case;
end if;

Wenn Sie mit anderen Einheiten interagieren - SPI-Schnittstellen, UARTs usw. - ist der FSM normalerweise wieder die beste Methode.

Beim FPGA-Design gibt es zwei Hauptklassen von Operationen:

  • Kombinatorik, also die Umsetzung logischer Ausdrücke .
  • Getaktete Operationen, mit anderen Worten das Anschließen an Latches (z. B. D-Typ-Flip-Flops) oder in Programmierbegriffen; Implementierung von Arbeitsabläufen .

Wie Sie vielleicht wissen, gibt es eine Grenze dafür, wie groß Ihre kombinatorischen Schaltungen sein können. Jedes Logikgatter hat eine Zeitverzögerung, wenn das Eingangssignal von "0" auf "1" ansteigt, dauert es einige Zeit, bis sich der Ausgang auf die richtige Antwort stabilisiert. Wenn Sie es zu weit kaskadieren, werden Sie feststellen, dass die Ausgabe nicht synchron sein und Fehler erzeugen kann.

Die Lösung hierfür besteht natürlich darin, sich auf Verriegelungen zu verlassen. Zu einem bestimmten Zeitpunkt sampeln Sie die Ausgabe und halten sie bis zum nächsten Mal gültig. Hier kommen getaktete Operationen ins Spiel.

Daraus folgt natürlich das Pipelining . Wenn Sie nicht alles in einem Zyklus erledigen können, teilen Sie ihn in mehrere Teile auf, wobei jeder Teil das Teilergebnis an den nächsten Teil weiterleitet. Der letzte Teil präsentiert das Endergebnis, normalerweise N Zyklen später.

Aber manchmal ist es nicht so einfach. Wenn das Problem erfordert, dass je nach Zustand (normalerweise Zeit oder einige externe Eingaben) etwas anderes passiert , dann sind Finite State Machines (FSM) die logischste Lösung.

FSMs reduzieren die logische Komplexität. "Wenn dies und das passiert, sollten wir dies tun." Beispiele sind angebracht, aber bedenken Sie, dass die Ausführung einer CPU eigentlich nur eine riesige Zustandsmaschine ist.

Wenn Sie Ihr Problem in eine endliche Anzahl von Schritten unterteilen können, bei denen der Übergang von einem Schritt zum anderen möglicherweise unterschiedlich ist , sollten Sie in der Regel die Verwendung eines FSM in Betracht ziehen. Da dies bei weitem das häufigste Szenario ist, werden Sie feststellen, dass Sie FSMs ziemlich häufig verwenden werden.

Ich würde eine gegenteilige Antwort geben. Wann sollte man kein FSM verwenden?

Wenn Ihre Operationsfolge mehr als etwa 30 Zustände benötigt, sind Sie wahrscheinlich entweder:

  • Der Versuch, das Verhalten mehrerer Maschinen in einem Zustand zu mischen. Beispielsweise kann in einem seriellen Protokoll das Erzeugen der Bits aus Bytes durch eine FSM erfolgen, das Zusammensetzen von Bytes zum Erzeugen von Rahmen durch eine andere.
  • Beim Schreiben von Software sollte die Zustandsmaschine typischerweise durch Mikrocode ersetzt werden.

Nicht triviale digitale Systeme, die fast immer synchron sind und daher einen Takt verwenden, können als eine Reihe von Registern betrachtet werden, die Daten mit kombinatorischer Logik zwischen ihnen speichern, die die Daten verarbeitet. Die Daten werden durch binäre Signale dargestellt. Diese Leitung, die eine einzelne Leitung sein oder sich zu anderen Leitungen verzweigen kann, wird als Datenpfad bezeichnet. Die Daten fließen auf diesem Weg und werden über boolesche Operationen verarbeitet, die über kombinatorische Logik implementiert sind, die Zwischenergebnisse werden im Register gespeichert und dann von der nächsten kombinatorischen Logik verarbeitet. So sieht auch "Pipeline" aus.

Wir brauchen eine Zustandsmaschine, um diesen Datenfluss im Grunde zu steuern, dh wir treffen Entscheidungen auf der Grundlage von Zwischenergebnissen darüber, wie die Daten verarbeitet werden, ob sie linear fortgesetzt werden, ob sie verzweigt, ob sie gelöscht oder überschrieben werden einen neuen Eingabewert, speichern wir den Ausgabewert und senden ein Signal, das dem anderen Teil der Hardware mitteilt, dass die Datenverarbeitung in diesem Teil der Hardware abgeschlossen ist, oder neue Daten von einem anderen Teil des Designs anzufordern; Diese Dinge sind einfach in einer Hochsprache zu schreiben. In VHDL, wo wir Hardware beschreiben, erstellen wir dafür eine Zustandsmaschine.

Was ich gegeben habe, ist eine sehr allgemeine Beschreibung, die möglicherweise keinen vollständigen Sinn ergibt. Es ist sinnvoll, wenn Sie tatsächlich ein System entwerfen, in dem Sie es verwenden müssen.