Les solutions traditionnelles comme les ASI dédiés ou les enregistreurs à moteur logiciel ne répondent pas souvent à la combinaison de débits en temps réel, de flexibilité et de faible latence exigée par les systèmes modernes. Les arcades de porte programmables sur le terrain (FPGA) permettent de combler cette lacune en fournissant une plate-forme matérielle entièrement personnalisable qui permet de traiter les flux de données à des débits gigabit-par-seconde tout en s'adaptant à des normes d'interface en évolution.

Pourquoi les FPGA pour l'enregistrement de données à haute vitesse

Parallélisme et latence déterministe

Contrairement aux microprocesseurs ou aux DSP qui exécutent les instructions de façon séquentielle, les FPGA traitent les données dans un véritable matériel parallèle. Pour un enregistreur de données, cela signifie que vous pouvez simultanément capturer les données de plusieurs canaux à grande vitesse, effectuer le prétraitement (filtrage, décimation ou formatage), tamponner les résultats et les diffuser au stockage, le tout dans un matériel sans frais CPU.

Flexibilité de l'interface

Les enregistreurs de données à grande vitesse doivent être reliés à diverses sources : convertisseurs analogiques à numériques (ADC) utilisant des LVDS ou JESD204B, interfaces multimédias haute définition (HDMI), liaisons de caméras ou bus de capteurs personnalisés. Les FPGA prennent en charge nativement une large gamme de standards d'entrées-sorties (LVDS, HSTL, SSTL, paires différentielles) et de transceivers série (GTP, GTX, GTH) capables de multi-gigabit par seconde.

Reconfiguration en vol

De nombreuses applications d'enregistrement exigent que le système s'adapte à différents taux de données, à différents nombres de canaux ou à différents schémas d'encodage sans modification matérielle. Les FPGA peuvent être partiellement ou entièrement reconfigurés sur une liaison PCIe, Ethernet ou une interface de configuration dédiée.Cette capacité permet à une carte d'enregistrement unique de servir plusieurs missions, par exemple, la commutation entre une configuration radar 12 bits 1 GPSS de 4 canaux et un mode d'enregistrement radio (SDR) de 500 MSPS de 16 bits 2 canaux.

Principales considérations de conception et compromis

Architecture de débit et de mémoire

Le débit de données dans un enregistreur est limité par trois facteurs : le taux de capture d'entrée, la capacité de tampon interne et la bande passante de sortie vers le support de stockage (p. ex., tableau SSD, DRAM, ou lien de streaming). Le débit le plus défavorable doit dépasser le débit moyen de données pour éviter la perte de données.

  • RAM sur bloc de puce (BRAM):[ Capacité rapide, double-port, mais limitée (généralement quelques dizaines de Mbits sur les FPGA modernes). Utilisé pour les petits FIFO, tampons de ligne, ou stockage de coefficients.
  • DRAM externe (DRD3/DRD4/LPDDR4):[ Haute capacité (multiple GB) mais avec des contraintes de latence et de bande passante. Un contrôleur DDR bien conçu (souvent un fournisseur IP) combiné à une connexion AXI multicanaux peut fournir des dizaines de bande passante agrégée GB/s.
  • SRAM externe:[ Latence inférieure à DRAM mais densité inférieure; utile pour les FIFO profonds où un temps d'accès déterministe est nécessaire.
  • Stockage série haute vitesse:[ Ecrire directement aux SSD NVMe sur NVMe au-dessus de PCIe ou via un pont dédié (p. ex. Xilinx QDMA IP). Cela décharge les grandes séries de données vers la mémoire non volatile, mais nécessite un contrôle de flux soigneux pour éviter le débordement de tampon.

Dans VHDL, vous modélisez ces mémoires comme des tableaux ou des primitives de fournisseurs instantanés. Par exemple, un FIFO générique utilisant BRAM peut avoir un paramètre de profondeur défini au moment de la compilation, tandis qu'un tampon soutenu par DDR serait interface à travers un moteur AXI4 à mémoire.

Domaines de l'horloge et la métastabilité

Les enregistreurs de données à grande vitesse couvrent de façon intrinsèque plusieurs domaines d'horloge : l'horloge d'échantillonnage ADC (potentiellement > 1 GHz), l'horloge en tissu FPGA (souvent une division de la référence de l'émetteur), l'horloge de contrôleur mémoire et l'horloge d'interface système. Le franchissement de ces domaines nécessite des techniques de synchronisation appropriées. La méthode la plus robuste est d'utiliser des FIFO à double horloge (avec des horloges indépendantes lues et écrites).

La métastabilité des tongs utilisés pour le croisement de la porte d'horloge peut être atténuée en utilisant deux ou plusieurs registres de synchronisation.

signal async_sig, sync1, sync2 : std_logic;
begin
 process(clk) begin
 if rising_edge(clk) then
 sync1 <= async_sig;
 sync2 <= sync1;
 end if;
 end process;

Pour les bus de données, il est plus sûr d'utiliser un protocole de poignée de main ou un FIFO plutôt que plusieurs synchroniseurs monobit.

Fermeture des horaires aux hautes fréquences

Les modèles FPGA ciblant des débits de données supérieurs à plusieurs centaines de MHz doivent respecter des exigences de configuration rigoureuses et tenir compte des contraintes de temps.

  • Pipe Stages: Insérez des registres (phases de pipeline) dans des chemins de données à fort ou long débit. Par exemple, un adder 64 bits dans une boucle d'accumulateur doit être enregistré à la fois sur l'entrée et la sortie.
  • Clock Patinage et Horloge Activer:[ Utiliser des signaux compatibles avec l'horloge plutôt que de lancer l'horloge pour éteindre la logique; horloges fermées créent des risques de synchronisation et contribuent à l'écheveau.
  • Synthèse Attributs:[ Utilisez des directives spécifiques au fournisseur (p. ex., garde, syn préservation et max fanout) pour guider les outils. Dans VHDL, elles sont souvent ajoutées comme commentaires: .
  • Planification des glissières:[ Grouper la logique à grande vitesse dans les régions dédiées de la FPGA pour réduire les retards d'interconnexion.

Architecture système d'un enregistreur à haute vitesse typique

Entrée en début de ligne

Pour les DCA JESD204B, il s'agit d'un IP d'émetteur JESD204B (généralement fourni par le fournisseur FPGA) qui gère la synchronisation des voies, le brouillage et la détection d'erreurs. Pour les DCA LVDS parallèles, vous utilisez un désérialiseur (ISERDES dans Xilinx, ALTDDIO IN dans Intel) pour convertir des bits série à grande vitesse en mots parallèles au rythme de l'horloge en tissu.

Prétraitement et mise en forme des données

Les données brutes saisies peuvent nécessiter des opérations en temps réel avant le stockage:

  • Décimation/Filtrage:[ Réduction du taux de données par des facteurs entiers à l'aide de filtres à intégration-comb (CIC) ou de filtres FIR mis en œuvre sous forme de blocs à accumulation multiple (MAC).
  • Conversion vers un format standard:[ Envelopper les données dans des images avec des horodatages, des identifiants de canaux et des mots de vérification d'erreurs (p. ex. CRC).
  • Zero Overhead:[ En mode éclatement, vous devrez peut-être insérer des marqueurs de pause ou remplir de zéros pour maintenir un flux de bits constant depuis l'interface de stockage.

Tous les modules de traitement doivent être pipelinelés pour maintenir la latence faible. Par exemple, un filtre de décimation polyphasée peut être structuré comme un tableau systolique de tranches DSP connectées par des chemins de données enregistrés.

Contrôle de la pression et du débit

Un tampon élastique (FIFO) découple le domaine de l'horloge de capture du domaine de l'horloge de stockage. La profondeur de la FIFO doit être dimensionnée en fonction de la longueur de rupture de l'entrée la plus défavorable et du temps nécessaire pour que l'interface de stockage commence à écrire. Une approche commune consiste à utiliser une FIFO avec des seuils programmables presque complets et presque vides pour générer des signaux de contre-pression.

Interface de stockage

La dernière étape est l'écriture des données tamponnées sur un support persistant.

  • PCIe DMA to Host RAM or SSD: Utiliser un moteur DMA (par exemple Xilinx QDMA ou Intel P-Tile DMA) pour transférer des données directement dans la mémoire du système ou un lecteur NVMe. Le FPGA agit comme un point de référence PCIe et le pilote gère les anneaux tampons.
  • Drive directe de mémoire Flash:[ Pour les enregistreurs autonomes, vous pouvez interagir avec NAND flash ou eMMC en utilisant un contrôleur implémenté dans VHDL. Ceci est plus complexe mais fournit une solution entièrement intégrée.
  • Liens série haute vitesse (p. ex. Aurora, GDS):[ Pour la diffusion sur un serveur distant ou une autre carte FPGA.

Chaque interface a son propre protocole et mécanisme de contrôle de flux. Par exemple, un enregistreur basé sur PCIe utiliserait une chaîne de descripteurs DMA à mémoire ou à flux; la VHDL doit gérer les demandes de transaction, la gestion de l'achèvement et le contrôle de flux basé sur le crédit.

Étapes de mise en œuvre dans la LHDV

Définir l'entité et les ports de premier niveau

Commencez par énumérer toutes les interfaces externes : entrées d'horloge (horloges de référence et horloge en tissu d'une PLL), entrées de données des ADC, signaux de configuration et interface de stockage (p. ex., paires différentielles PCIe).

entity high_speed_recorder is
 generic (
 ADC_CHANNELS : integer := 2;
 DATA_WIDTH : integer := 16;
 FIFO_DEPTH : integer := 1024
 );
 port (
 ref_clk_p, ref_clk_n : in std_logic; -- differential reference
 adc_data : in std_logic_vector(ADC_CHANNELS * DATA_WIDTH - 1 downto 0);
 adc_clk : in std_logic; -- sample clock
 pcie_tx_p, pcie_tx_n : out std_logic_vector(3 downto 0);
 pcie_rx_p, pcie_rx_n : in std_logic_vector(3 downto 0);
 -- more ports...
 );
end entity;

Horloge instantanée des fournisseurs et des I/O Primitives

Utilisez des primitives spécifiques au fournisseur pour l'horlogerie (p. ex. Xilinx MMCM/PLL) et les I/O à grande vitesse (ISERDES, OSERDES ou enveloppes d'émetteurs). Dans VHDL, ces derniers sont souvent appelés comme des instantanées de composants.

mmcm_inst : entity work.mmcm_wrapper
 generic map (
 MULT => 8.0,
 DIV => 1
 )
 port map (
 clkin1 => ref_clk,
 clkout0 => fabric_clk,
 clkout1 => transceiver_clk,
 locked => pll_locked
 );

Construire le chemin de données

Écrire la logique de contrôle qui traite les données du désérialisateur d'entrée à la sortie FIFO. Utiliser la conception hiérarchique : chaque bloc fonctionnel (désérialisateur, FIFO, données de matière) est une entité VHDL distincte. Connectez-les via des bus de signal (tableaux std logic vector) qui suivent un protocole cohérent, comme une poignée de mains simple valide/prête. Une poignée de main typique :

-- Producer side
if rising_edge(clk) then
 if ready = '1' and valid = '1' then
 -- data transferred
 end if;
end if;
-- Consumer side
if rising_edge(clk) then
 if valid = '1' and ready = '1' then
 -- consume data
 end if;
end if;

Ce protocole est la base de AXI4-Stream, qui est largement supporté par les bibliothèques de fournisseurs.

Détails de la mise en œuvre de la FIFO

Voici une version améliorée d'un FIFO à double horloge avec des paramètres génériques et des drapeaux presque pleins/presque vides. Contrairement à l'extrait original, cette version utilise l'arithmétique entier pour la gestion du compteur et du pointeur, et utilise le code gris pour l'adresse traversant le domaine horloge pour éviter les erreurs de synchronisation multibit. Un vrai design utiliserait des primitives fournisseurs (par exemple, Xilinx FIFO Generator) pour la production, mais une implémentation VHDL illustre la logique :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity dual_clock_fifo is
 generic (
 DATA_WIDTH : integer := 64;
 ADDR_WIDTH : integer := 10 -- depth = 2^ADDR_WIDTH
 );
 port (
 wr_clk : in std_logic;
 wr_rst : in std_logic;
 wr_en : in std_logic;
 wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0);
 full : out std_logic;
 almost_full : out std_logic;

 rd_clk : in std_logic;
 rd_rst : in std_logic;
 rd_en : in std_logic;
 rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0);
 empty : out std_logic;
 almost_empty: out std_logic
 );
end entity;

architecture rtl of dual_clock_fifo is
 type memory_t is array (0 to (2**ADDR_WIDTH)-1) of std_logic_vector(DATA_WIDTH-1 downto 0);
 signal mem : memory_t;

 signal wr_ptr, rd_ptr : unsigned(ADDR_WIDTH-1 downto 0);
 signal wr_gray, rd_gray : unsigned(ADDR_WIDTH-1 downto 0);
 signal wr_count, rd_count : unsigned(ADDR_WIDTH downto 0); -- include overflow bit
 signal sync_wr_ptr, sync_rd_ptr : unsigned(ADDR_WIDTH-1 downto 0);
 signal sync_wr_count, sync_rd_count : unsigned(ADDR_WIDTH downto 0);
begin
 -- Write pointer and memory write
 process(wr_clk) begin
 if rising_edge(wr_clk) then
 if wr_rst = '1' then
 wr_ptr <= (others => '0');
 wr_count <= (others => '0');
 elsif wr_en = '1' and full = '0' then
 mem(to_integer(wr_ptr)) <= wr_data;
 wr_ptr <= wr_ptr + 1;
 wr_count <= wr_count + 1;
 end if;
 wr_gray <= (wr_ptr srl 1) xor wr_ptr; -- binary to gray
 end if;
 end process;

 -- Read pointer and memory read
 process(rd_clk) begin
 if rising_edge(rd_clk) then
 if rd_rst = '1' then
 rd_ptr <= (others => '0');
 rd_count <= (others => '0');
 elsif rd_en = '1' and empty = '0' then
 rd_count <= rd_count + 1;
 rd_ptr <= rd_ptr + 1;
 end if;
 rd_gray <= (rd_ptr srl 1) xor rd_ptr;
 end if;
 end process;

 -- Synchronize write pointer to read clock domain
 process(rd_clk) begin
 if rising_edge(rd_clk) then
 sync_wr_ptr <= wr_gray;
 end if;
 end process;

 -- Synchronize read pointer to write clock domain
 process(wr_clk) begin
 if rising_edge(wr_clk) then
 sync_rd_ptr <= rd_gray;
 end if;
 end process;

 -- Full and empty detection using gray-code pointers (simplified)
 -- Full when (wr_gray ~ sync_rd_ptr) and top two bits differ
 full <= '1' when (wr_gray(ADDR_WIDTH-1) /= sync_rd_ptr(ADDR_WIDTH-1) and
 wr_gray(ADDR_WIDTH-2 downto 0) = sync_rd_ptr(ADDR_WIDTH-2 downto 0)) else '0';
 empty <= '1' when (rd_gray = sync_wr_ptr) else '0';

 -- Almost flags (threshold defined by constants)
 almost_full <= '1' when wr_count >= 2**ADDR_WIDTH - 8 else '0';
 almost_empty <= '1' when rd_count <= 8 else '0';

 rd_data <= mem(to_integer(rd_ptr));
end rtl;

Intégration et câblage de haut niveau

Dans l'architecture de haut niveau, vous actualisez l'interface PLL, desérializer, FIFO et de stockage, puis les connectez en utilisant des tâches de signal. Faites attention à réinitialiser la polarité et l'horloge permettent la propagation. Une meilleure pratique est d'utiliser des réinitialisateurs synchrones entraînés par les horloges de domaine respectives, affirmés asynchronement mais désaffirmés synchronement, pour éviter la métastabilité.

Stratégie d'essai et de vérification

Simulation avec testbenches

Simulez chaque module de manière indépendante : vérifiez que le FIFO est correctement lu/écrit, que les conditions de sous-flux/dépassement sont respectées et que le pointeur est suivi par un code gris. Utilisez un banc de test auto-vérifié qui génère des données aléatoires et compare la sortie après un délai. Pour le système complet, créez un banc de test qui émule l'interface ADC avec un générateur de motif programmable et un modèle de mémoire pour le côté de stockage.

Fermeture et vérification après le placement

Après synthèse et mise en œuvre, effectuer une analyse statique des chronométrages dans tous les domaines de l'horloge. Porter une attention particulière aux chemins à cycle multiple (p. ex., les opérations de lecture de mémoire qui se terminent après plus d'un cycle d'horloge) et aux faux chemins (p. ex., les synchroniseurs de domaine à horloge croisée). Utiliser les rapports de fournisseurs pour identifier les défauts de configuration ou tenir les loans, puis ajouter des étapes de pipeline ou ajuster les contraintes.

Validation matérielle

Prototyper sur une carte de développement FPGA avec des ressources similaires (p. ex. Xilinx Kintex-7, Virtex-7 ou AMD Zynq UltraScale+). Injecter des modèles de test connus (comme une rampe répétitive ou une séquence PRBS) à l'entrée ADC et vérifier que les données capturées correspondent au modèle attendu après stockage ou re-reprise. Utilisez des analyseurs logiques intégrés (p. ex. Xilinx ILA) pour surveiller les signaux internes comme les drapeaux d'état FIFO et écrire permet en temps réel.

Applications et exemples du monde réel

  • Radar et Lidar Systems:[ Enregistrer les données brutes I/Q de plusieurs canaux à plusieurs fréquences de prélèvement de GHz pour la détection et la classification des cibles post-traitement. Les FPGA gèrent la conversion numérique en temps réel et tamponnent les données aux SSD sur SATA ou PCIe.
  • Radio définie par logiciel (SDR):[ Les enregistreurs à haute vitesse capturent le spectre à large bande (p. ex., bande passante instantanée de 400 MHz) pour une analyse ultérieure des modes d'interférence ou de l'intelligence du signal.
  • Physique de haute énergie: Dans les expériences au CERN ou dans des installations similaires, les données provenant de milliers de canaux détecteurs doivent être enregistrées pour les rafales courtes. Les FPGA agrégent les données, ajoutent des horodatages et écrivent à DRAM avant de les lire lentement sur les serveurs de stockage.
  • Ultrasons médicaux: La formation d'images en temps réel et à haute résolution nécessite la capture de plusieurs canaux transducteurs à des dizaines de MHz par canal.

Conclusion

La conception d'un enregistreur de données à grande vitesse basé sur FPGA est une tâche d'ingénierie sophistiquée qui exige une compréhension approfondie de la conception numérique, de la gestion des horloges, des hiérarchies de mémoire et des protocoles d'interface. VHDL fournit la précision et le contrôle nécessaires pour mettre en œuvre des chemins de données personnalisés qui fonctionnent aux limites du matériel. En abordant méthodiquement le débit, le tamponnage, le franchissement du domaine horloge et la fermeture du temps, les ingénieurs peuvent construire des enregistreurs qui répondent aux exigences des applications les plus difficiles.

Pour plus de détails, consultez le Xilinx Memory Resources Guide pour les primitives BRAM et FIFO détaillés ou le Intel FPGA High-Speed I/O Design Guide[ pour l'utilisation des émetteurs-récepteurs.