FPGA

Les FPGA sont construits selon une philosophie très différente des circuits programmables simples et des CPLD étudiés dans la section précédente.

Architecture typique d’un FPGA

Un FPGA est construit comme une matrice de blocs logiques interconnectés. Ces blocs portent différents noms selon les constructeurs :

Chaque bloc contient des cellules logiques qui peuvent être configurées séparément pour réaliser des fonctions logiques particulières.

Architecture typique d'un FPGA

Sur la figure ci-dessus, nous avons représenté une architecture à trois niveaux telle qu’on peut la rencontrer dans les FPGA du constructeur Xilinx.

Des blocs d’entrée/sortie (IOB pour Input/Output Block) permettent de configurer la connexion entre les blocs logiques et les broches du circuit.

Les blocs logiques et les blocs d’entrée/sortie sont reliés à un réseau de routage configurable qui peut être très sophistiqué sur les FPGA récents.

Contenu d’un bloc logique

Dans cette section, nous prenons pour exemple la famille de FPGA Artix-7 de Xilinx que nous utiliserons dans les activités pratiques. Dans les composants de cette famille, chaque bloc logique est composé de deux tranches (slices). Il existe différents types de tranches que nous ne décrirons pas toutes en détail.

Tranche SLICEL Xilinx série 7

La figure ci-dessus représente le schéma d’une tranche SLICEL (source Xilinx Inc. : UG474 – 7 series FPGAs Configurable Logic Blocks User Guide). Elle contient :

  1. Des générateurs de fonctions combinatoires (LUT pour Look-Up Table) à six entrées et deux sorties (en bleu sur la figure).
  2. Des éléments de mémorisation configurables en tant que verrous ou bascules D (en jaune).
  3. Des multiplexeurs pour aiguiller les sorties des LUT ou des bascules vers les sorties du bloc (en vert).
  4. De la logique de calcul de retenue pour accélérer les opérations d’addition ou de soustraction (en rose).

Look-Up Tables

Une LUT réalise une fonction logique combinatoire dont on connaît la table de vérité. Elle repose sur le même principe qu’une PROM (Programmable Read-Only Memory) : une LUT est une mémoire, typiquement accessible en lecture seule, qui associe une valeur à chaque combinaison de son entrée adresse.

Dans les FPGA Artix-7 de Xilinx, une LUT est construite autour d’une RAM de 64 bits, dont le contenu est initialisé au démarrage. Elle peut être utilisée de deux manières différentes :

  1. Comme une fonction combinatoire à six entrées et une sortie (6 bits d’adresse font 64 combinaisons). Voir schéma de gauche ci-dessous, où la sortie O5 est inutilisée.
  2. Comme une fonction combinatoire à cinq entrées et deux sorties (5 bits d’adresse font 32 combinaisons, et deux bits sont accessibles à une même adresse). Voir schéma de droite ci-dessous, où l’entrée A6 est forcée à 1.

Une LUT dans un FPGA Xilinx Artix-7

Exemple : comparateur

Ci-dessous, nous utilisons une LUT pour vérifier si deux vecteurs aa et bb de trois bits sont égaux. Voici un extrait de la table de vérité et le schéma correspondant :

a2a_2 a1a_1 a0a_0 b2b_2 b1b_1 b0b_0 ee
0 0 0 0 0 0 1
0 0 0 0 0 1 0
0 0 1 0 0 0 0
0 0 1 0 0 1 1
0 0 1 0 1 0 0
0 1 0 0 0 1 0
0 1 0 0 1 0 1
0 1 0 0 1 1 0
0 1 1 0 1 0 0
0 1 1 0 1 1 1
0 1 1 1 0 0 0
1 0 0 0 1 1 0
1 0 0 1 0 0 1
1 0 0 1 0 1 0
1 0 1 1 0 0 0
1 0 1 1 0 1 1
1 0 1 1 1 0 0
1 1 0 1 0 1 0
1 1 0 1 1 0 1
1 1 0 1 1 1 0
1 1 1 1 1 0 0
1 1 1 1 1 1 1

Utilisation d'une LUT pour comparer deux vecteurs de 3 bits

Exemple : additionneur

Dans cet autre exemple, nous utilisons les deux sorties d’une LUT pour calculer la somme de deux entiers aa et bb sur deux bits (ce circuit ne produira pas le bit de retenue) :

a1a_1 a0a_0 b1b_1 b0b_0 s1s_1 s0s_0
0 0 0 0 0 0
0 0 0 1 0 1
0 0 1 0 1 0
0 0 1 1 1 1
0 1 0 0 0 1
0 1 0 1 1 0
0 1 1 0 1 1
0 1 1 1 0 0
1 0 0 0 1 0
1 0 0 1 1 1
1 0 1 0 0 0
1 0 1 1 0 1
1 1 0 0 1 1
1 1 0 1 0 0
1 1 1 0 0 1
1 1 1 1 1 0

Utilisation d'une LUT pour additionner deux vecteurs de 2 bits

Utilisations avancées des LUT

RAM distribuée

Dans l’utilisation typique d’une LUT, sa RAM de configuration est accessible en écriture au moment d’initialiser son contenu, et en lecture seule au cours de son fonctionnement.

Cependant, certaines LUT peuvent également fournir un accès en écriture à tout moment. On peut alors utiliser un assemblage de LUT, non plus pour réaliser des fonctions combinatoires, mais pour mémoriser des données au cours du fonctionnement du circuit.

Par exemple, dans un FPGA Artix-7, on peut réaliser une RAM de 1024 octets (8192 bits) en utilisant 128 LUT.

On parle alors de RAM distribuée, par opposition à des blocs de RAM spécialisés qui sont également disponibles dans de nombreux FPGA (voir plus bas).

Registres à décalage

En interne, dans une LUT les éléments de mémorisation sont câblés en chaîne pour former un registre à décalage.

Si votre application utilise de nombreux, ou de longs registres à décalage, les bascules D disponibles dans chaque tranche peuvent être insuffisantes. Dans un FPGA Artix-7, chaque LUT peut être utilisée comme un registre à décalage de 32 bits.

Autres composants disponibles dans les FPGA

Comme nous venons de le voir, les blocs logiques sont très polyvalents. Ils suffisent à réaliser un grand nombre de fonctions numériques, mais ont l’inconvénient d’être peu optimisés pour des usages spécifiques.

L’utilisation de LUT pour effectuer des opérations mathématiques, comme par exemple des multiplications, ou comme RAM distribuée est possible mais coûteuse et peu performante : dans les deux cas, le circuit occupera un grand nombre de LUT et sera beaucoup plus lent qu’un circuit multiplieur ou RAM optimisé.

Pour cette raison, en plus des blocs logiques, les FPGA peuvent contenir des composants dédiés comme :

Réalisation d’un système numérique avec un FPGA

Aujourd’hui, les FPGA permettent de réaliser des systèmes complexes pour lesquels une réalisation à la main serait trop difficile. Le développement d’un tel système s’appuie sur des langages de modélisation et des outils automatiques en suivants ces étapes :

  1. Conception : représenter l’architecture du système comme une interconnexion de blocs fonctionnels ; modéliser le comportement de ces blocs sous la forme de graphes d’états, de chronogrammes, etc.
  2. Description : exprimer le comportement des blocs et leurs interconnexions en utilisant un langage de description de matériel, comme VHDL ou Verilog.
  3. Synthèse : représenter le circuit comme une interconnexion de LUT, de bascules D, ou de composants spécialisés de votre FPGA.
  4. Placement et routage : attribuer à chaque composant du circuit un emplacement dans la matrice du FPGA ; déterminer le chemin des signaux entre les blocs logiques utilisés.
  5. Génération d’un bitstream : générer un fichier binaire représentant la configuration complète du FPGA.

Nous illustrons ces étapes en nous appuyant sur l’exemple de la partie commande du robot autonome. La conception a déjà été réalisée dans le chapitre sur les automates.

Description en VHDL

Le langage VHDL est abordé plus loin dans ce document et un chapitre est consacré à la description des automates. Nous n’entrerons pas dans le détail ici.

Voici le code VHDL décrivant la partie commande du robot autonome, sous la forme d’une machine de Mealy associée à un compteur :

entity RobotAutonome is
    generic(
        DUREE_DE_ROTATION : positive
    );
    port(
        clk, reset : in std_logic;
        ca, cg, cd : in std_logic;
        mga, mgr, mda, mdr : out std_logic
    );
end RobotAutonome;

architecture Automate of RobotAutonome is
    signal fr : std_logic;
    signal tr_reg : natural range 0 to DUREE_DE_ROTATION - 1;

    type State is (RM, SM, RG, RD);
    signal state_reg : State;
begin
    p_state_reg : process(clk, reset)
    begin
        if reset = '1' then
            state_reg <= RM;
        elsif rising_edge(clk) then
            case state_reg is
                when RM =>
                    if ca = '1' then
                        state_reg <= RD;
                    elsif cg = '1' then
                        state_reg <= RG;
                    end if;
                when SM =>
                    if cg = '0' then
                        state_reg <= RG;
                    elsif ca = '1' then
                        state_reg <= RD;
                    end if;
                when RG | RD =>
                    if fr = '1' then
                        state_reg <= RM;
                    end if;
            end case;
        end if;
    end process p_state_reg;

    mga <= not ca when state_reg = RM or state_reg = SM else
           not fr when state_reg = RD                   else '0';
    mda <= not ca when state_reg = RM or state_reg = SM else
           not fr when state_reg = RG                   else '0';
    mgr <= not fr when state_reg = RG                   else '0';
    mdr <= not fr when state_reg = RD                   else '0';

    p_tr_reg : process(clk)
    begin
        if rising_edge(clk) then
            case state_reg is
                when RM | SM =>
                    tr_reg <= 0;
                when RG | RG =>
                    if fr = '1' then
                        tr_reg <= 0;
                    else
                        tr_reg <= tr_reg + 1;
                    end if;
            end case;
        end if;
    end process p_tr_reg;

    fr <= '1' when tr_reg = DUREE_DE_ROTATION - 1 else '0';
end Automate;

Synthèse

À partir du code source ci-dessus, l’outil de synthèse de Xilinx produit un premier schéma dans lequel les instructions VHDL ont été traduites directement par des composants logiques : des portes logiques (RTL_INV, RTL_OR), des multiplexeurs (RTL_MUX), un additionneur (RTL_ADD), des registres (RTL_REG), une table de correspondance (RTL_ROM).

Commande du robot autonome (RTL)

Le schéma après synthèse est composé de 13 LUT, de 10 bascules D (FDRE) et de buffers d’entrée/sortie (IBUF, OBUF) :

Commande du robot autonome (synthèse)

Placement-routage

Le schéma suivant représente la disposition des composants utilisés dans le FPGA (en bleu). Nous observons que le circuit utilise quatre tranches réparties dans deux blocs. À titre d’exemple, nous avons affiché les connexions en entrée/sortie d’une LUT.

Commande du robot autonome (placement)

Par curiosité, nous pouvons visualiser le routage des signaux (en vert sur la figure ci-dessous). À droite, nous observons deux régions rectangulaires avec de nombreuses connexions qui s’entrecroisent. Elles correspondent à des matrices de connexions configurables (switch box) qui relient les blocs logiques entre eux.

Commande du robot autonome (routage)

En pratique, nous avons rarement l’occasion de visualiser ces schémas qui sont peu lisibles et difficiles à mettre en relation avec le code source VHDL dont ils sont issus.

Technologies de configuration

Les FPGA actuellement disponibles utilisent trois types de technologies pour réaliser les connexions configurables : de la RAM statique (SRAM), de la mémoire Flash ou des antifusibles.

La plupart des constructeurs proposent des FPGA à base de SRAM. Leur principal défaut est qu’ils perdent leur configuration lorsqu’ils ne sont pas alimentés. Pour contourner cette difficulté, ils sont généralement conçus pour être reliés à une mémoire Flash externe dans laquelle ils lisent leur configuration à chaque mise sous tension.

Les FPGA à base d’antifusibles sont une spécialité du constructeur Microsemi (anciennement Actel). Ils sont utilisés en priorité dans les systèmes avioniques et spatiaux soumis à des rayonnements ionisants, comme les particules alpha qui peuvent altérer le contenu des mémoires. Ils sont également réputés pour être plus rapides et moins consommateurs d’énergie que les FPGA à SRAM.