L'acquisizione di dati ad alta velocità è un requisito fondamentale in campi che vanno dalla telemetria aerospaziale alla rappresentazione medica e allo strumento scientifico. Le soluzioni tradizionali come ASIC o registratori basati sul software spesso non riescono a soddisfare la combinazione di throughput in tempo reale, flessibilità e bassa latenza richiesta dai sistemi moderni.

Perché FPGAs per la registrazione di dati ad alta velocità

Parallelismo e Latency disinfettante

A differenza dei microprocessori o dei DSP che eseguono le istruzioni sequenziali, i dati di processo FPGAs in un vero hardware parallelo. Per un registratore di dati, questo significa che è possibile catturare simultaneamente i dati da più canali ad alta velocità, eseguire la preelaborazione (filtrazione, decimazione o formattazione), buffer i risultati e stream loro a storage, tutto in hardware senza overhead della CPU.

Flessibilità dell'interfaccia

I registratori di dati ad alta velocità devono interfacciarsi con una varietà di fonti: convertitori analogici a digitali (ADC) utilizzando LVDS o JESD204B, interfacce multimediali ad alta definizione (HDMI), collegamenti per fotocamera o bus per sensore personalizzati.

Riconfigurabilità in volo

Molte applicazioni di registrazione richiedono il sistema per adattarsi a diverse velocità di dati, conteggi dei canali o schemi di codifica senza modifiche hardware. FPGAs può essere parzialmente o completamente riconfigurato su un collegamento PCIe, Ethernet o un'interfaccia di configurazione dedicata. Questa capacità consente a una scheda di registrazione unica di servire più missioni, ad esempio, passando tra una configurazione radar a 12-bit 1 GSPS a 4 canali e una modalità di registrazione a 16-canali 500 MSPS.

Considerazioni chiave di progettazione e Trade-Offs

Architettura di memoria e di produzione

Il throughput dei dati in un registratore è limitato da tre fattori: la velocità di acquisizione dell'ingresso, la capacità di buffering interna e la larghezza di banda di scrittura di uscita al supporto di archiviazione (ad esempio, SSD array, DRAM o collegamento di streaming).

  • Sul-chip block RAM (BRAM):[] Veloce, a doppio porto, ma limitato in capacità (tipicamente alcune decine di Mbit su FPGA moderna).
  • DRAM esterno (DDR3/DDR4/LPDDR4):[] Alta capacità (multiple GB) ma con vincoli di latenza e larghezza di banda. Un controller DDR ben progettato (spesso un IP del fornitore) combinato con un interconnessione AXI multicanale può fornire decine di GB/s larghezza di banda aggregata.
  • SRAM esterno:[ Latenza inferiore al DRAM ma la densità inferiore; utile per i FIFO profondi dove è necessario un tempo di accesso deterministico.
  • Memorizzazione seriale ad alta velocità:[] Scritto direttamente a SSD NVMe su NVMe su PCIe o tramite un ponte dedicato (ad esempio, Xilinx QDMA IP). Questo consente di scaricare grandi set di dati sulla memoria non volatile, ma richiede un controllo accurato del flusso per evitare il sovraflusso del buffer.

In VHDL, si modellano questi ricordi come array o primitivi di vendor istantaneo. Ad esempio, un FIFO generico che utilizza BRAM potrebbe avere un parametro di profondità impostato al momento di compilazione, mentre un buffer DDR-backed si interfaccia attraverso un motore di memoria AXI4.

Domini e Metastabilità dell'orologio

I registratori di dati ad alta velocità coprono intrinsecamente più domini di clock: l'orologio del campione ADC (pocizialmente > 1 GHz), l'orologio del tessuto FPGA (spesso una divisione del riferimento del transceiver), l'orologio del controller di memoria e l'orologio dell'interfaccia di sistema.

La metastability in infradito utilizzato per l'attraversamento del dominio dell'orologio può essere mitigata utilizzando due o più registri sincronizzanti.

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;

Per gli autobus di dati, è più sicuro usare un protocollo handshake o un FIFO piuttosto che sincronizzatori a singolo bit multipli.

Chiusura di tempo alle alte frequenze

I progetti FPGA che mirano a tassi di dati superiori a diverse centinaia di MHz devono soddisfare le severe impostazioni e tenere vincoli di tempo. VHDL strutturato in modo insufficiente, come logica combinata profondamente nidificata, multisalatori di larghezza o assegnazioni di blocco all'interno dei blocchi di processo, può portare a violazioni di tempismo.

  • Pipe Stages:[] Inserisci registri (stadi di pipeline) in percorsi dati ad alta fanout o lunghi. Ad esempio, una scala a 64 bit all'interno di un loop di accumulatore dovrebbe essere registrata sia su input che su output.
  • Clock Gating e Clock Enable:[] Usa segnali di attivazione dell'orologio piuttosto che gating l'orologio per spegnere la logica; orologi gated creano rischi di tempismo e contribuiscono a skew.
  • Attributi di sintesi:[]] Utilizzare direttive specifiche del fornitore (ad esempio, mantenere, sin preserve e max fanout) per guidare gli strumenti.
  • Pianificatore a freddo:[] Gruppo logica ad alta velocità nelle regioni dedicate della FPGA per ridurre i ritardi di interconnessione.

Architettura di sistema di un tipico registratore ad alta velocità

Input Fronte-End

Il primo modulo nel percorso dati cattura i dati dalla fonte esterna. Per JESD204B ADCs, questo comporta un IP transceiver JESD204B (solitamente fornito dal fornitore FPGA) che gestisce la sincronizzazione della corsia, lo scrambling e il rilevamento di errori.

Preelaborazione e formattazione dei dati

I dati acquisiti crudi possono richiedere operazioni in tempo reale prima della memorizzazione:

  • Decimazione/Filtro:[[] Ridurre la velocità dei dati tramite fattori interi utilizzando filtri a base di integratori-comb (CIC) cascaded o filtri FIR implementati come blocchi moltiplica-accumulati (MAC).
  • Conversione a Formato Standard:[]] I dati di Wrapping in frame con timestamp, ID canale e parole di controllo degli errori (ad esempio, CRC).
  • Zero Overhead:[ In modalità di esplosione, potrebbe essere necessario inserire marcatori di pausa o riempire con zero per mantenere un flusso di bit costante dall'interfaccia di archiviazione.

Tutti i moduli di elaborazione devono essere condotti per mantenere bassa latenza. Ad esempio, un filtro di decimazione polifase può essere strutturato come una serie sistolica di fette DSP collegate da percorsi di dati registrati.

Controllo di buffer e flusso

Un buffer elastico (FIFO) decouplifica il dominio dell'orologio di cattura dal dominio dell'orologio di archiviazione. La profondità FIFO deve essere dimensionata in base alla lunghezza di scoppio dell'ingresso peggiore e al tempo necessario per l'interfaccia di archiviazione per iniziare a scrivere. Un approccio comune è quello di utilizzare un FIFO con soglie programmabili quasi complete e quasi nulle per generare segnali di stampa posteriore.

Interfaccia di stoccaggio

La fase finale scrive i dati bufferati a un mezzo persistente. Opzioni includono:

  • PCIe DMA per Host RAM o SSD:[] Utilizzando un motore DMA (ad esempio, Xilinx QDMA o Intel P-Tile DMA) per trasferire i dati direttamente nella memoria del sistema o un drive NVMe.
  • Direct Drive of Flash Memory:[] Per i registratori standalone, è possibile interfacciarsi con NAND flash o eMMC utilizzando un controller implementato in VHDL. Questo è più complesso ma fornisce una soluzione completamente integrata.
  • Collegamenti seriali ad alta velocità (ad esempio, Aurora, GDS): Per lo streaming su un server remoto o su un'altra scheda FPGA.

Ogni interfaccia ha un proprio protocollo e un meccanismo di controllo del flusso, ad esempio un registratore basato su PCIe utilizzerebbe una catena di descrittori DMA con mappa della memoria o con flusso di flusso; il VHDL deve gestire le richieste di transazione, la gestione del completamento e il controllo del flusso basato sul credito.

I passaggi di implementazione in VHDL

Definire l'Inserzione e i Porti Top-Level

Iniziare elencando tutte le interfacce esterne: ingressi orologio (orologio di riferimento e orologio in tessuto da un PLL), ingressi di dati da ADC, segnali di configurazione e interfaccia di archiviazione (ad esempio, coppie differenziali 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;

Istantaneo Venditore Orologio e I/O Primitivi

Utilizzare i primitivi specifici per il venditore per l'orologio (ad esempio, Xilinx MMCM/PLL) e I/O ad alta velocità (ISERDES, OSERDES, o wrapper per transceiver). In VHDL, questi sono spesso chiamati come istantanee dei componenti. Ad esempio, per istantanare un MMCM Xilinx con cambio di fase dinamico, si potrebbe scrivere:

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
 );

Costruire il percorso dati

Scrivere la logica di controllo che elabora i dati dal deserializzatore di input al FIFO di uscita. Utilizzare il design gerarchico: ogni blocco funzionale (deserializzatore, FIFO, formatore di dati) è un'entità VHDL separata. Collegarli tramite bus di segnale (std logic vector arrays) che seguono un protocollo coerente, come un semplice handshake valido / pronto.

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

Questo protocollo è la base di AXI4-Stream, che è ampiamente supportato da librerie di fornitori.

Dettagli di implementazione FIFO

Diversamente dal ceppet originale, questa versione utilizza aritmetica integer per la gestione dei contatori e dei puntatori, e impiega il codice grigio per l'indirizzo che attraversa il dominio dell'orologio per evitare errori di sincronizzazione multibit. Un vero disegno userebbe i primitivi dei fornitori (ad esempio, l'implementazione di XiHDlinx FIFO, ma la logica di VFO Generator).

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;

Integrazione e cablaggio Top-Level

Nell'architettura di alto livello, istanza PLL, deserializer, FIFO e interfaccia di archiviazione, quindi collegarli con le assegnazioni del segnale. Prestare attenzione per ripristinare polarità e orologio abilitare la propagazione. Una migliore pratica è quella di utilizzare reimpostazioni sincrone guidate dai rispettivi orologi di dominio, asserzionate asincronamente ma sincronizzate, per evitare la metastability.

Test e strategia di verifica

Simulazione con Testbenches

Simulare ogni modulo in modo indipendente: verificare il FIFO per le sequenze di lettura/scrittura corrette, le condizioni di sottoflusso/overflow e il rilevamento dei punti di grigio. Utilizzare un banco di prova autocontrollo che genera dati casuali e confronta l'output dopo un ritardo. Per il sistema completo, creare un banco di prova che emula l'interfaccia ADC con un generatore di pattern programmabile e un modello di memoria per il lato di archiviazione.

Verifica di chiusura e post-lattamento

Dopo la sintesi e l'implementazione, eseguire analisi statiche di tempistica su tutti i domini dell'orologio. Prestare particolare attenzione ai percorsi multi-ciclo (ad esempio, le operazioni di lettura della memoria che completano dopo più di un ciclo di orologio) e ai percorsi falsi (ad esempio, i sincronizzatori cross-clock-domain).

Convalida hardware

Prototipo su un forum di sviluppo FPGA con risorse simili (ad esempio, Xilinx Kintex-7, Virtex-7 o AMD Zynq UltraScale+). Iniezione modelli di test noti (come una rampa di ripetizione o una sequenza PRBS) all'ingresso ADC e verifica dei dati acquisiti corrisponde al modello previsto dopo lo storage o il rientro.

Applicazioni e esempi reali-mondiali

  • Radar e Lidar Systems:[] Registrare dati I/Q grezzi da più canali a più velocità di campionamento GHz per il rilevamento e la classificazione di destinazione post-elaborazione.
  • Radio Definita da software (SDR): I registratori ad alta velocità catturano lo spettro a banda larga (ad esempio, 400 MHz di larghezza di banda istantanea) per un'analisi successiva dei modelli di interferenza o dell'intelligenza del segnale. Il registratore spesso include filtri di decimazione che permettono la selezione dinamica della larghezza di banda durante la cattura.
  • Fisica ad alta energia:[] In esperimenti al CERN o simili, i dati provenienti da migliaia di canali di rivelatore devono essere registrati per brevi scoppi. FPGAs aggregare i dati, aggiungere timestamp e scrivere a DRAM prima di lento lettura ai server di archiviazione.
  • Ultrasound medico:[ La formazione di immagini in tempo reale e ad alta risoluzione richiedono la cattura di più canali di trasduttore a decine di MHz per canale.

Conclusioni

Progettare un registratore di dati ad alta velocità basato su FPGA è un compito di ingegneria sofisticato che richiede una comprensione approfondita del design digitale, della gestione dell'orologio, delle gerarchie di memoria e dei protocolli di interfaccia. VHDL fornisce la precisione e il controllo necessari per implementare percorsi di dati personalizzati che operano ai limiti dell'hardware.

Per ulteriori informazioni, consultare il Guida alle risorse della memoria Xilinx per i primitivi BRAM e FIFO dettagliati o Intel FPGA High-Speed I/O Design Guide per l'uso del ricetrasmettitore. Inoltre, il libro VHDL di riferimento avanzato[FLT]