Debug in-circuit di FPGA

La crescente capacità logica dei dispostivi programmabili consente oggi di realizzare complessi System-On-Chip che includono le principali funzionalità di sistema in un unico dispositivo. Tuttavia, unitamente alla complessità del sistema, crescono le problematiche legate alla fase di verifica del progetto che tendono ad incidere negativamente sul time-to-market del prodotto. Identify è un software per il debug in circuit di FPGA sviluppato tempo fa da Synplicity, leader nell’ambito dei tool EDA per logiche programmabili ed ASIC.

Introduzione

La figura 1a mostra il flusso di processo che viene tradizionalmente seguito nel progetto di sistemi complessi mediante logiche  programmabili. Il codice sorgente viene verificato funzionalmente creando opportuni test-bench che cercano di coprire  la maggior  parte  dei  casi reali. I tool di sintesi e place&route traducono quindi il codice in un file di programmazione per il dispositivo. Per favorire il debug nelle situazioni reali, un numero limitato di pin della FPGA vengono riservati dal progettista per monitorare mediante un analizzatore di stati logici segnali di controllo interni.

Tuttavia, in seguito alla crescente complessità dei progetti, è divenuto piuttosto difficile prevedere tutti i possibili casi in simulazione; allo stesso modo, il numero ridotto di segnali che è possibile monitorare non sempre consente di individuare correttamente i malfunzionamenti del circuito. Si è quindi avvertita sempre più insistentemente l’esigenza di tool per il debug in circuit sulla falsariga degli ambienti di emulazione/debugger diffusamente utilizzati per la validazione degli applicativi software.

La figura 1b mostra come il flusso di processo nel progetto di logiche programmabili si modifica utilizzando Synplicity Identify. Prima di essere sintetizzato, il progetto viene ‘strumentato’;  in altri termini, direttamente nel codice sorgente, come mostrato in seguito, vengono definiti i segnali che si intende monitorare nella successiva fase di debug. Il tool, in maniere automatica, crea una struttura logica che permette di acquisire nel tempo il valore di tali segnali e definire complesse condizioni di trigger. Tale logica accessoria è del tutto equivalente ad un analizzatore di stati logici integrato nel dispositivo e quindi in grado di accedere virtualmente a tutti i segnali di controllo e stato interni. Non è necessario prevedere a priori test-point nel circuito stampato come in un approccio classico; internamente alla FPGA viene creata una memoria per i segnali da monitorare. La disponibilità di risorse per tale scopo diventa quindi l’unico vincolo alla quantità di campioni ed al numero di segnali che è possibile acquisire. In fase di debug, da remoto, è possibile controllare le condizioni di trigger in corrispondenza delle quali acquisire il buffer di memoria. In questo modo si è in grado di eseguire la simulazione funzionale, che nell’approccio classico precede la fase di sintesi, direttamente sul target reale riducendo significativamente i tempi di prototyping e debug. Gli elementi principali che sono inclusi nell’ambiente Identify sono:

  • l’IICE (Intelligent In-Circuit  Emulator), la logica accessoria integrata nel progetto logico del dispositivo per il monitoring dei segnali
  • l’Instrumentor, il tool per l’integrazione automatica dell’IICE
  • il Debugger, il software per  il controllo da remoto dell’IICE, l’acquisizione dei segnali in corrispondenza delle condizioni di trigger ed il display di questi come forme d’onda

I paragrafi successivi riportano una descrizione più dettagliata dei tre elementi.

Figura 1. Flusso di progetto classico (a) e mediante Identify (b)

Figura 1: flusso di progetto classico (a) e mediante Identify (b)

IICE

L’IICE costituisce, come accennato in precedenza, l’analizzatore di stati logici che viene integrato all’interno  della  FPGA. Comprende  principalmente  i seguenti blocchi funzionali:

  • il JTAG controller, per la comunicazione con il debugger via porta JTAG;
  • il sampler, per l’acquisizione dei test point;
  • il controller, per la gestione delle condizioni di trigger.

Numerosi parametri possono essere configurati per i diversi blocchi. Nel caso ad esempio della comunicazione JTAG, è possibile specificare se si intende utilizzare un eventuale controller builtin disponibile nel dispositivo od il Tap-Controller di Synplify, sintetizzato utilizzando logica utente. In questo caso, qualora non sia disponibile una risorsa dedicata per la distribuzione del clock JTAG, è possibile specificare la creazione di una struttura hardware master/slave instrinsecamente skew-resistant. Nel caso del sampler, invece, sono configurabili la dimensione del buffer di memoria utilizzato per l’acquisizione dei segnali di test, il tipo di risorsa hardware da utilizzare (flip-flop o RAM embedded qualora disponibili), il clock di campionamento ed il relativo fronte attivo. Nel caso si intenda monitorare segnali appartenenti a domini di clock distinti, è possibile istanziare  nel progetto unità IICE multiple. Sono inoltre attivabili due interessanti modalità di campionamento dei segnali:

  • qualified sampling: in questo  caso viene acquisito un singolo campione in corrispondenza di ogni occorrenza del trigger consentendo di osservare l’evoluzione del sistema su un periodo piuttosto lungo di tempo;
  • always-armed triggering: il buffer di memoria viene salvato in corrispondenza del trigger ma il sistema resta armato fino al successivo trigger od interruzione. Tale modalità è tipicamente utilizzata nell’analisi di sistemi che utilizzino un pattern di trigger costante  (ad esempio  un  ciclo  di bus) richiedendo casualmente l’acquisizione del buffer di memoria.

Allo stesso  modo  sono  disponibili tre diverse modalità di trigger nella configurazione del controller:

  • simple triggering, basato su singoli watchpoints o breakpoints. I primi rappresentano i segnali che vengono monitorati ed in base al cui valore è possibile impostare le condizioni di trigger. I breakpoint sono invece istruzioni condizionali che provocano un evento di trigger quando vengono eseguite.
  • complex  counter  triggering,  per il quale sono definite le seguenti modalità:
    • events  mode:  l’acquisizione  del  buffer  di memoria  viene  richiesta  in  corrispondenza
      dell’ n-mo trigger;
    • cycles mode: l’acquisizione del buffer di memoria viene richiesta n cicli di clock dopo l’occorrenza del trigger;
    • watchdog mode: l’acquisizione del buffer di memoria viene richiesta se il trigger non si verifica entro n cicli di clock dal momento in cui il sistema è armato;
    • pulsewidth mode: l’acquisizione del buffer di memoria viene richiesta se la condizione di trigger è verificata per n cicli di clock consecutivi.
  • state machine triggering, per la creazione di sequenze predefinite di eventi di trigger al termine delle quali richiedere l’acquisizione del buffer di memoria.

Identify Instrumentor

L’Instrumentor (figura 2) è l’ambiente che consente la creazione ed inserzione automatica dell’IICE nel progetto di riferimento.

Figura 2. La finestra principale dell’Instrumentor

Figura 2: la finestra principale dell’Instrumentor

Come osservato in precedenza, il tool opera direttamente sul codice sorgente per definire watchpoints e breakpoints. Come mostrato in figura 2, visualizzando infatti il codice all’interno di Identify, vengono automaticamente evidenziati i segnali che possono essere associati a watchpoints (sottolineati e colorati in blu) e le istruzioni che possono costituire breakpoints (indicate da un bottone grigio a margine).

Cliccando direttamente sulle icone di riferimento è possibile abilitare o escludere la corrispondente condizione. In questo modo l’intero processo di ‘strumentazione’ del progetto viene reso estremamente intuitivo ed immediato. Per rendere ancora più agevole l’intero processo, inoltre,  la  schermata principale dell’Instrumentor, come mostrato in figura 2, presenta nella parte sinistra una finestra di lavoro che ricostruisce la gerarchia dl progetto. Questa evidenzia, nel caso ad esempio di codice in linguaggio VHDL, l’entità top-level, le architetture disponibili, le istruzioni di istanziazione di componenti, di definizione di processo, di controllo di flusso, i sottoprogrammi ed i blocchi. È possibile elencare in una finestra di popup tutti i segnali e le istruzione che possono costituire watchpoints e breakpoints evidenziando quelli già strumentati. In base ai watchpoints e breakpoints definiti, l’Instrumentor modifica il codice sorgente per l’inserzione dell’IICE e la connessione dei relativi probe. Tale codice modificato può quindi essere sintetizzato come nell’approccio classico; in particolare vengono generati script TCL per l’esecuzione dei tool di sintesi più diffusi tra i quali Synplify o Leonardo. Una console riporta in formato testuale tutti i comandi che sono stati eseguiti; è possibile salvare l’intera lista come script come TCL da eseguire in successive iterazioni.

Identify Debugger

La figura 3 mostra la finestra di strumentazione di Identify Debugger, del tutto simile alla schermata analoga dell’Instrumentor.

Figura 3. La finestra principale del Debugger

Figura 3: la finestra principale del Debugger

Diversamente da questa, tuttavia, vengono evidenziati ora nel codice sorgente soltanto le istruzioni che sono state definite come breakpoints ed i segnali scelti come watchpoints. Cliccando sul relativo pulsante verde di riferimento, ad esempio, è possibile abilitare come trigger i breakpoints; cliccando invece in corrispondenza dei segnali si apre la finestra che consente di definire il valore (o la transizione di valori) rispetto a cui creare il trigger. Nel caso di complex counter trigger, inoltre, è possibile selezionare la modalità relativa e definire il valore del contatore. Nel caso, invece, di utilizzo di una configurazione di trigger basata su macchina a stati, è abilitata all’interno del Debugger una finestra (figura 4) con semplice interfaccia grafica. Sono elencati tutti gli stati previsti in fase di strumentazione ed è quindi possibile definire per ognuno di essi la relativa condizione di trigger oltre alle transizioni tra stati.

Figura 4. La finestra per il triggering basata macchine a stati

Figura 4: la finestra per il triggering basata macchine a stati

L’insieme di watchpoints e breakpoints abilitati o, più in generale, la configurazione di trigger impostata  costituisce quella  che  viene chiamata ‘attivazione’ del sistema. Il Debugger consente di salvare sottoforma di script e richiamare successivamente una qualunque attivazione. Il comando di run permette di armare il sistema. Vengono comunicate all’IICE le condizioni di trigger che sono state configurate; il Debugger resta quindi in attesa di riceve i campioni memorizzati nel buffer, qualora una di queste si verifichi. Una volta acquisito, l’intero buffer può successivamente essere scorso in avanti o indietro a partire da un suo qualunque campione; ad ogni passo, il corrispondente valore dei watchpoints viene aggiornato direttamente nella finestra che mostra il codice sorgente consentendo in questo modo di seguire l’evoluzione del sistema come sequenza di istruzioni eseguite. In certi casi, tale approccio risulta più intuitivo e permette un debug più efficace. Diversamente, è possibile esportare l’intero buffer in un formato compatibile con i più diffusi viewer di forme d’onda.

 

Scrivi un commento

EOS-Academy
EOS-Academy