FPGA-Doppelpufferstrategie

Ich arbeite an einem FPGA-Projekt, bei dem eine Host-CPU eine 10.240 x 16-Bit-Nachschlagetabelle in die FPGA-Logik schreibt. Um dies zu implementieren, habe ich einen On-Chip-Speicher verwendet, um die Werte zu speichern und sie auszulesen, wenn sie fertig sind.

Ein externer Trigger/Go-Impuls startet einen Verarbeitungszyklus, der mehrere hunderttausend Taktzyklen dauert. Sobald wir diesen Trigger erhalten, muss der Zustand der 10.240 x 16 LUT eingefroren oder zwischengespeichert werden, damit er während des Verarbeitungszyklus verwendet werden kann. Unglücklicherweise müssen die Daten ziemlich bald nach diesem "GO"-Impuls verfügbar sein, so dass nicht genügend Zeit vorhanden ist, um eine vollständige Pufferkopie durchzuführen.

Der Host muss auch in der Lage sein, einige Werte der Nachschlagetabelle kontinuierlich zu aktualisieren, während der aktuelle Zyklus ausgeführt wird, um sich für den nächsten Verarbeitungszyklus einzurichten. Um beide Fälle zu ermöglichen (den Status der Nachschlagetabelle zu speichern, aber auch den Host jederzeit aktualisieren zu lassen), denke ich, dass der Ping/Pong-Stil mit doppelter Pufferung der richtige Weg ist: Der Host schreibt in einen Puffer, bis wir dazu kommen "GO"-Befehl, dann schreibt der Host zum anderen. Die FPGA-Logik liest immer aus dem Puffer, in den nicht geschrieben wird.

Da der Host jedoch nicht alle 10.240 x 16-Werte neu schreibt, wenn er seine sporadischen Aktualisierungen durchführt, "verwirft" der Puffer, in den nicht geschrieben wird, die Aktualisierungen im Wesentlichen, während er eingefroren ist.

Gibt es eine neuartige Möglichkeit, mit diesem Szenario umzugehen? Ich denke, es muss eine Art Puffer-Resynchronisierungsprozess geben, sobald der Puffer aufgetaut ist.

Gibt es Leistungsgründe, warum Sie keinen dedizierten "Konfigurations" -Puffer haben können, der beim GO-Impuls in den "Verarbeitungs" -Puffer eingeklinkt wird?

Antworten (2)

Eine mögliche Strategie könnte darin bestehen, veraltete Bits zu verwenden. Keine Ahnung, ob das Standardterminologie ist, aber es ähnelt einem schmutzigen Bit. Das Schreiben eines neuen Eintrags löscht das entsprechende Stale-Bit im entsperrten Puffer und setzt das Bit im gesperrten Puffer. Lassen Sie nach dem Umschalten der Puffer eine interne Kopierroutine jeden als veraltet markierten Eintrag im nicht gesperrten Puffer aus dem gesperrten Puffer in den nicht gesperrten Puffer übertragen. Auf diese Weise werden neue Daten, die während des Kopiervorgangs geschrieben werden, nicht überschrieben, und alle alten Aktualisierungen sollten beibehalten werden. Das einzige, was Sie tun müssen, ist sicherzustellen, dass genügend Zeit für den Kopiervorgang zwischen den Pufferwechseln bleibt, oder Sie benötigen eine Art Optimierung, um zu verfolgen, welche Einträge veraltet sind, damit Sie nicht alles wiederholen müssen sie, was den Kopiervorgang beschleunigt.

Eine andere mögliche Strategie könnte darin bestehen, die aktualisierten Einträge zu speichern, während ein einzelner Puffer gesperrt ist, und dann nur diese Aktualisierungen anzuwenden, wenn er entsperrt ist. Wenn nur eine Handvoll Einträge aktualisiert werden, ist dies möglicherweise effizienter. Die Aktualisierungen könnten als verknüpfte Liste oder ähnliche Datenstruktur gespeichert werden, so dass die Liste effizient durchlaufen werden kann, während mehrere Aktualisierungen an derselben Stelle zusammengeführt werden können.

Wenn es keine Gründe gibt, dies nicht zu tun, würde ich Folgendes tun:

  • Haben Sie zwei Puffer von 10240 * 16 Bits
  • Füllen Sie einen davon mit der CPU aus, nennen Sie ihn den "Konfigurieren"-Puffer
  • Kopieren Sie auf dem Go Pulse den Puffer „Konfigurieren“ in den Puffer „Verarbeiten“. Wenn Sie Ihren GO-Impuls einen Zyklus senden können, bevor die Verarbeitung der Daten tatsächlich beginnt, können Sie sogar zusätzliches Muxen vermeiden, wenn der Konfigurationspuffer für den ersten Zyklus der Datenverarbeitung verwendet wird. Dies würde auch Back-to-Back-Aktualisierung und -Verarbeitung ermöglichen (würde jedoch wahrscheinlich etwas Arbeit im Kernel-Space der CPU erfordern).
Das würde nur funktionieren, wenn sich die Puffer im verteilten RAM befinden, wo Sie vollständig parallele Übertragungen haben könnten, damit es in einem Takt funktioniert, möglich, aber es ist eine MENGE Fläche und wird wahrscheinlich beim Routing ersticken.
@DanMills Sicher, aber unter der Annahme von verteiltem RAM ist dies weniger Fläche als zwei vollwertige Puffer, in denen jedes Bit gemuxt werden muss.