Aller au contenu

Very High Speed Integrated Circuit Hardware Description Language/VHDL et machines à états algorithmiques

Leçons de niveau 15
Une page de Wikiversité, la communauté pédagogique libre.
Début de la boite de navigation du chapitre
fin de la boite de navigation du chapitre
En raison de limitations techniques, la typographie souhaitable du titre, « Very High Speed Integrated Circuit Hardware Description Language : VHDL et machines à états algorithmiques
Very High Speed Integrated Circuit Hardware Description Language/VHDL et machines à états algorithmiques
 », n'a pu être restituée correctement ci-dessus.

Tout ce qui a été traité dans conception et VHDL fait partie du niveau de spécification RTL (Register Transfer Level). Le niveau d'abstraction abordé maintenant est appelé ESL (Electronic System level).

Quand la fonction à synthétiser devient complexe, la synthèse doit être décomposée en deux parties : un chemin de données et un séquenceur (ou unité de contrôle) destiné à ordonnancer les opérations sur ce chemin de données. En automatisme le chemin de données est plutôt appelé partie opérative. On utilisera cette terminologie parfois. La synthèse correspondante nécessite alors des raisonnements spécifiques : cette décomposition demande une expérience d'autant plus grande que les parties utilisées se décomposent elles-même en sous-parties... Disons pour simplifier que le niveau simple correspond à ce que l’on fait en schéma logique traditionnel : utiliser des composants simples existants. C'est ce niveau qui va nous intéresser maintenant. Dans ce chapitre nous n'aborderons que superficiellement le sujet, avec des exemples.

Terminologie :

Note : Wikipédia ne distingue pas les deux termes.

Utilisations de compteurs (comme chemin de données)

[modifier | modifier le wikicode]

Le compteur de passages est un exemple utilisant des compteurs séquencés comme chemin de données. Son fonctionnement est le suivant :

  • si, d’abord le capteur gauche détecte (une personne), puis le capteur droit détecte (la même personne), on incrémente un compteur.
  • dans le cas contraire, si le capteur droit est activé avant le capteur gauche, on décrémente.

Cela permet de connaître, par exemple, le nombre de personnes dans une salle.

En logique traditionnelle, le chemin de données est composé par deux compteurs 74190 et le séquenceur par une machine à états. Le séquenceur peut être réalisé avec des composants programmables simples (SPLD). Donnons-en un schéma de principe :

Le compteur de passages, son séquenceur et ses compteurs

Dans cette figure, on distingue, à gauche, le séquenceur avec dans sa partie supérieure les entrées et sorties. Il y a deux sorties : H (horloge) et DU (Down/Up = Comptage/décomptage) et 4 entrées : clk (horloge), droite et gauche qui sont reliés aux capteurs et Init qui parle d'elle-même. A droite, le chemin de données est constitué par deux compteurs 74190 cascadés et commandés par le signal H qui compte ou décompte suivant la valeur de DU. Il est inutile de chercher la documentation du 74190 pour comprendre la suite. Cet ensemble est simplement destiné à compter ou décompter en BCD et afficher sur deux afficheurs 7 segments.

Cet exemple n’est pas conforme aux règles d'assemblage du séquentiel. En effet l'horloge H de la partie opérative est réalisée par les actions du séquenceur et donc par du combinatoire ce qui est fortement déconseillé lorsqu'on veut faire une synthèse fiable. Nous avons eu l’occasion de réaliser cet ensemble soit avec un PAL et deux 74190, soit dans un seul composant de type FPGA en utilisant un modèle VHDL du 74190 et pour ces deux réalisations on obtient un aléa de fonctionnement. Nous le présentons donc ici, à seul titre d'exemple, car il a l'avantage d’être simple à comprendre.

Début d’un principe
Fin du principe


Pour comprendre le rapport entre cette règle et notre schéma, je vous propose de lire ou relire le chapitre description par graphe d'état du cours de logique séquentielle. Vous y réviserez le fait qu'une sortie ou action est programmée de manière combinatoire. Or pour notre compteur de passage la sortie "H" est réalisée par une action, ... et c’est là qu'est le problème !

Nous allons donc nous intéresser au respect des règles d'assemblage du séquentiel et modifier en conséquence l'exemple ci-dessus du compteur de passages.

Mise en conformité du compteur de passages

[modifier | modifier le wikicode]

Le principe de base est de changer la partie chemin de données (les compteurs). On lui ajoute une entrée « en_tick » de validation synchrone. Le fonctionnement des compteurs est alors le même qu'un 74190 tant qu'en_tick=1 tandis que le compteur reste figé si en_tick=0. La partie séquenceur est alors chargée de réaliser les deux signaux « UD » et « en_tick » mais pas l'horloge. L'horloge sera commune au séquenceur et au chemin de données, mais pour un bon fonctionnement on s'arrangera pour que ces deux parties soient sensibles à un front différent : par exemple front montant pour le séquenceur et front descendant pour le chemin de données.

C'est une bonne chose lorsqu’il s'agit de faire la séparation entre le séquenceur et le chemin de donnée de considérer que le premier fonctionne sur un type de front d'horloge (par exemple montant) et le deuxième sur le front complément (par exemple descendant).

Lorsque les horloges du chemin de données et celle de la partie commande sont décalées dans le temps les raisonnements sont en général relativement simples. Mais en principe il faut mieux que tout le monde fonctionne sur un même front !

Début d’un principe
Fin du principe

Modifier le chemin de données ci-dessus pour qu’il utilise la même horloge que la partie séquenceur. Donner le schéma global correspondant en montrant qu’il faudra ajouter deux états à la machine d'états du séquenceur (que se passe-t-il si l’on reste dans S4 ?).

La gestion de l'écran VGA déjà présentée en exercice dans un WIKIBOOK Conception et VHDL, utilise deux compteurs ayant chacun son horloge. La deuxième horloge provient d'une comparaison c'est-à-dire d'un circuit combinatoire ce qui ne respecte pas la règle de base de l'assemblage du séquentiel (pas d'horloge provenant de combinatoire). Comment modifier le montage pour avoir un montage complètement synchrone (même horloge pour les deux compteurs) ?

Remarque : la façon de procéder de l'exercice original fonctionne correctement en fait car le combinatoire n’est pas pur mais synchronisé sur front descendant. Cela reste cependant une technique non recommandée. On essaie d'expliquer pourquoi maintenant.


Début d’un principe
Fin du principe

Le schéma référencé dans l'exercice 2 ne satisfaisait pas cette règle : deux compteurs ayant une horloge différente étaient contigus. Vous pouvez objecter, à juste titre, que le schéma était un schéma de principe et non un schéma d'implantation. Mais dans ce cas, ne pas oublier cette règle quand on implémente. Ne pas oublier aussi que VHDL ne vous aidera guère à respecter cette règle : nous voulons dire qu’il n'y a pas moyen de spécifier en VHDL des localisations de composants... en tout cas pour le VHDL standard et portable, mais chaque fabricant propose ses propres constructeurs pour réaliser ces placements.

Utilisation de registres (comme chemin de données)

[modifier | modifier le wikicode]

Nous nous trouvons dans la situation suivante : nous disposons de plusieurs registres qui forment ce que l’on appelle notre chemin de données, et nous désirons synthétiser un circuit qui les utilise. Ce circuit peut être combinatoire ou séquentiel. Nous allons appréhender cela avec un exemple de calcul de PGCD. Son calcul est réalisé à l'aide de l’algorithme d'Euclide. Cet algorithme peut être décrit de manière récursive de la façon suivante :

  • a et b sont les deux valeurs dont on cherche le PGCD (avec a > b)
  • si b = 0 alors le PGCD est a autrement on recherche le PGCD de b et du reste de la division de a par b.

Cet algorithme est décrit par l'organigramme suivant :

Les FSMD (Finite State Machine with Data path)

[modifier | modifier le wikicode]

Nous avons eu l’occasion de présenter les automates finis (ou machines à états finis ou finite state machine FSM). Nous allons généraliser avec les (en) FSMD (Finite State Machine with Data path). La terminologie française associée est assez variée :

  • Automates Finis avec chemin de Données (AFD)
  • machines à registres (terme non référencé dans Wikipédia)
  • machines algorithmiques ou automates algorithmiques (termes non référencés dans Wikipédia)

Au delà de la terminologie, ce qui nous intéresse est un moyen de décrire le fonctionnement de ces machines. Nous avons appris à spécifier les automates finis à l'aide des graphes d'états (ou parfois des graphes d'évolutions) nous allons présenter maintenant notre manière de spécifier les machines à registres. Cela peut se faire avec des organigrammes dans lesquels on a la possibilité de décrire des transferts ou des opérations entre registres (appelés parfois organigramme fonctionnel).

Revenons sur notre exemple de calcul du PGCD. Il peut être décrit par l'organigramme :

Calcul du PGCD avec le reste de la division comme resource

Cet organigramme suppose que l’on sache réaliser l'opération T reçoit A rem B, c'est-à-dire le reste de la division de A par B. Pour comprendre, par l'exemple cet organigramme, prenons au départ A = nb1 = 8 et B = nb2 = 6.

  • B étant différent de 0, T <- 2 puis A <- 6 et B <- 2
  • B étant différent de 0 ,T <- 0 puis A <- 2 et B <- 0
  • c’est fini et le résultat est dans A soit 2.

Tout cela est bien gentil, mais, comme déjà exprimé, nécessite un composant capable de calculer le reste de la division. Si, comme la suite va le supposer, ce n’est pas le cas, il nous faut en plus réfléchir à la réalisation de cette opération. Une simple suite de soustractions fait l'affaire (si l’on s'arrête dès qu'un nombre plus petit que le diviseur est obtenu). Il nous faut donc modifier l'organigramme en conséquence :

Calcul du PGCD avec la soustraction comme resource

Une fois vérifié le fonctionnement de notre algorithme, il nous reste à le matérialiser. La partie chemin de données sera responsable de tous les transferts de registres et des calculs combinatoires (en général). Pour notre exemple, nous avons trois registres (A, B et T), quatre transferts de registres (T <- A, T <- A-B, A <- B et B <- T), un calcul d'une différence (A-B) et deux tests B=0? et T<B?. Voilà donc tout ce que doit être capable de faire la partie chemin de données. Il est temps de passer au concret.

La partie chemin de données

[modifier | modifier le wikicode]

La partie chemin de données est présentée maintenant :

Le chemin de données pour le calcul du PGCD

On a gardé, comme convention de couleurs, le bleu turquoise pour les parties séquentielles, ici les registres. Le vert est toujours réservé aux parties combinatoires : tests et calcul d'une différence. La nouveauté est l'apparition des boutons (en rouge). Ils ont été ajoutés pour pouvoir faire les transferts dans les registres de manière symbolique. Appuyez sur le bouton ArB et le registre A reçoit le contenu du registre B. On peut donc lire ArB : A reçoit B. Il en est de même pour les trois autres boutons, sauf qu'en ce qui concerne D, ce n’est pas vraiment un registre mais une sortie de composant combinatoire.

Nous allons présenter maintenant le programme VHDL réalisant cette partie. Commençons par l'entité :

library IEEE; 
use IEEE.std_logic_1164.all; 
use IEEE.std_logic_arith.all; 
use IEEE.STD_LOGIC_UNSIGNED.all;
-- déclarations des entrées et sorties 
entity chemin_donnees is 
  port(	ArB: in STD_LOGIC; 
        BrT: in STD_LOGIC; 
        TrA: in STD_LOGIC; 
        TrD: in STD_LOGIC; 
	e_load: in STD_LOGIC; 
	e_A: in STD_LOGIC_VECTOR(7 DOWNTO 0); 
	e_B: in STD_LOGIC_VECTOR(7 DOWNTO 0); 
	s_A: out STD_LOGIC_VECTOR(7 DOWNTO 0); 
	s_B: out STD_LOGIC_VECTOR(7 DOWNTO 0); 
	s_T: out STD_LOGIC_VECTOR(7 DOWNTO 0); 
	Beq0: out STD_LOGIC; 
	TinfB: out STD_LOGIC; 
	clk: in STD_LOGIC); 
end chemin_donnees;

Le lecteur perspicace aura remarqué la présence de e_A et e_B qui ne sont pas dessinés dans le schéma de la figure ci-dessus. Ces deux entrées sont destinées à mettre initialement des valeurs dans les deux registres A et B.

Intéressons-nous maintenant à l'architecture où l’on retrouve un process par registre et un process par partie combinatoire :

architecture chemin_donnees_arch of chemin_donnees is 
-- declaration des registres 
signal regA,regB,regT : STD_LOGIC_VECTOR(7 DOWNTO 0); 
begin 
-- gestion des registres 
reg_A:process(clk)begin 
  if clk'event and clk='0' then 
    if ArB='1' then 
	 regA <= regB; 
	 elsif e_load='1' then regA <= e_A; 
	else 
	 regA <= regA; 
	end if; 
  end if; 
end process; 
reg_B:process(clk)begin 
  if clk'event and clk='0' then 
    if BrT='1' then 
	 regB <= regT; 
	 elsif e_load='1' then regB <= e_B; 
	else 
	 regB <= regB; 
	end if; 
  end if; 
end process; 
reg_T:process(clk)begin 
  if clk'event and clk='0' then 
    if TrA='1' then 
	 regT <= regA; 
	elsif TrD='1' then 
	 regT <= regT - regB; 
	else 
	 regT <= regT; 
	end if; 
  end if; 
end process; 
-- partie combinatoire 
T_inf_B:process(regT,regB)begin 
  if regT < regB then 
    TinfB <='1'; 
  else 
    TinfB <='0'; 
  end if; 
end process; 
B_eq_0:process(regB)begin 
  if regB = "00000000" then 
    Beq0 <='1'; 
  else 
    Beq0 <='0'; 
  end if; 
end process; 
  s_A <= regA; 
  s_B <= regB; 
  s_T <= regT; 
end chemin_donnees_arch;

Voila, vous savez tout maintenant sur notre chemin de données.

La partie séquenceur

[modifier | modifier le wikicode]

La machine d'états doit réaliser le séquencement des opérations pour que le calcul se déroule correctement. La spécification de celui-ci se fait facilement à partir de l'organigramme déjà présenté. Donnons-la à l'aide d'un diagramme d'états :

Le séquenceur du PGCD

Le calcul est terminé lorsqu'on arrive dans l'état 6. Pour simplifier on a omis le retour de l'état 6 vers l'état « init »


Réaliser le calcul du PGCD complet en VHDL en reprenant le chemin de données présenté plus haut.

On initialise le registre A à 8 et B à 6. Un « start » nous fait passer dans l'état 0 puis dans l'état 1. Réaliser un chronogramme des évènements à l'aide du diagramme d'états du séquenceur (en figure ci-dessus) et à l'aide du schéma du chemin de données.

Retour sur les problèmes d'horloge

[modifier | modifier le wikicode]

Cette section est difficile à comprendre. Même si elle ne fait intervenir que des notions du niveau indiqué, il est conseillé d'avoir du recul sur les notions présentées pour bien assimiler ce qui suit. Cependant, ce contenu n'est pas fondamental et peut être sauté en première lecture.

Nous pensons qu’il n’est pas difficile de suivre le calcul du PGCD dans la section précédente car on a choisi de faire fonctionner la partie chemin de données et la partie séquenceur sur des fronts d'horloge différents. Mais qu'en est-il si l’on décide d’utiliser les mêmes fronts d'horloge pour les deux parties ? C'est la question à laquelle on va tenter de répondre dans cette section.

Dans cette section nous utiliserons indifféremment les GRAFCETs et les graphes d'états. L'établissement des équations de récurrences se fait de la même manière dans les deux cas. Elle est présentée dans un autre projet.

Certains auteurs estiment qu’il faut éviter des fronts d'horloge différents dans les montages synchrones. C'est la raison d’être de cette section.

Glissement sémantique

[modifier | modifier le wikicode]

Imaginons une étape (ou un état) réalisant l'incrémentation d'un compteur. Le GRAFCET peut s'interpréter comme (voir figure ci-dessous GRAFCET de gauche) :

  • nous arrivons dans l'étape 5
  • comme nous sommes dans l'étape 5, nous incrémentons le compteur Cmpt
  • et nous quittons l'étape 5

Rappel : nous ne restons jamais dans une étape à cause du "=1" des transitions.

L'utilisation d'une horloge commune pour le séquenceur (ou l'unité de contrôle) et pour les actions (notre action est ici séquentielle puisqu’il s'agit d'un compteur), mais avec des sensibilités différentes aux fronts, permet de garder cette interprétation :

  • nous arrivons dans l'étape 5 sur le deuxième front montant (du dessin ci-dessous à droite sur fond blanc)
  • comme nous sommes dans l'étape 5, nous incrémentons le compteur Cmpt sur le front descendant (en rouge dans le dessin ci-dessous)
  • et nous quittons l'étape 5 sur le troisième front montant (du dessin ci-dessous)

Voici la figure correspondante. Ce qui la caractérise est que le GRAFCET représente le fonctionnement du séquenceur et que l'action représente le fonctionnement du chemin de donnée :

Évolution du jeton sur front montant, action sur front descendant

On a représenté, à gauche le GRAFCET étudié (sur fond bleu), et en se déplaçant vers la droite, l'évolution des étapes actives en fonction des fronts de l'horloge (représentée au-dessous des évolutions). On montre aussi que l'incrémentation du compteur se produit sur un front descendant (en rouge).


Mais qu'en est-il si tout le monde fonctionne sur le même front d'horloge ?


Une nouvelle interprétation est nécessaire :

  • nous arrivons dans l'étape 5 sur le deuxième front montant (du dessin ci-dessous)
  • nous quittons l'étape 5 et nous incrémentons le compteur Cmpt sur le troisième front montant (du dessin ci-dessous)

En fait c’est au moment de quitter l'étape 5 qu'on incrémente.

Voici la figure correspondante. Ce qui la caractérise est que le GRAFCET représente le fonctionnement du séquenceur et que l'action représente le fonctionnement du chemin de données tous deux fonctionnant sur une même sensibilité aux fronts d'horloge :

Évolution du jeton sur front montant, action aussi sur front montant

Le principe de cette figure est identique à celle qui précède : à gauche le GRAFCET étudié et en se déplaçant vers la droite, l'évolution de ce GRAFCET.

La différence est minime, pourtant elle peut conduire à des erreurs assez subtiles, particulièrement si l'étape est suivie d'un test. C'est ce que nous nous proposons d'examiner dans la section suivante.


Mise à jour suivie d'un test

[modifier | modifier le wikicode]

Avant de présenter le problème un petit détour vers les ambiguïtés d'écriture nous semble utile.

L'écriture cmpt = cmpt+1 est une écriture ambiguë. Il faudrait mieux écrire que l’on pourrait traduire en français : l'état futur de cmpt sera cmpt+1 au prochain front d'horloge.


Maintenant le problème du test peut être exprimé facilement. Imaginons qu’il y ait un test cmpt=5 après l'étape 5 de la figure ci-dessus (au lieu du "=1"). Que doit-on tester, cmpt ou , autrement dit, l'état présent ou l'état futur ?

Si vous vous dites, c’est évidemment cmpt puisqu'on a écrit cmpt=5, eh bien, que vous dire ? Vous avez perdu, c’est qu’il faut tester !

Cahier des charges d'un exemple

[modifier | modifier le wikicode]

Nous allons traiter un exemple simple maintenant. La figure ci-dessous présente le GRAFCET exemple, à gauche, et le déroulement dans le temps de ce GRAFCET à droite (avec les valeurs du compteur).

Un GRAFCET comme exemple

Remarquez que quand le compteur passe à 3 on est déjà parti de l'étape 1 mais que le jeton reste bien trois fronts d'horloge dans l'étape une.

Programme VHDL

[modifier | modifier le wikicode]

Voici le programme VHDL correspondant :

-- programme VHDL correspondant au grafcet précédent
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all; -- WARP : use work.std_arith.all;
use ieee.std_logic_unsigned.all;
ENTITY graf1 IS 
PORT (Init,clk : IN std_logic;
     -- image des étapes
      o0,o1,o2 : OUT std_logic;
     -- image du compteur
      oCnt : OUT std_logic_vector(1 downto 0)
);
END graf1;
ARCHITECTURE agraf1 OF graf1 IS
-- les étapes proprement dit
SIGNAL x, xf : std_logic_vector(2 downto 0);
-- le compteur
SIGNAL Cnt,Cntf : std_logic_vector(1 downto 0);
BEGIN
  -- calcul des états futurs
    xf(0) <= x(2) or Init;
    xf(1) <= (x(0) and not Init) or (not (Cntf(1) and Cntf(0)) and x(1) and not Init); --test /= 3
    xf(2) <= x(1) and Cntf(1) and Cntf(0) and not Init; --test = 3
  PROCESS(clk) BEGIN
    IF (clk'event AND clk='1') THEN
-- équations de récurrences
      x(0) <= xf(0);
      x(1) <= xf(1);
      x(2) <= xf(2);
  -- et aussi sur le même front :
      Cnt <= Cntf;
    END IF;
  END PROCESS;
--équations de sorties ( le compteur)
  with x(1 downto 0) select
    Cntf <= "00" when "01",
            Cnt + "01" when "10",
            Cnt when others;
-- partie pour test bench
  o0 <= x(0);
  o1 <= x(1);
  o2 <= x(2);
  oCnt <= Cnt;
END agraf1;

Pour qu'aucune confusion ne soit possible, il faut mieux séparer le calcul de l'état futur de sa mise à jour. Ici, tout ce qui concerne le futur contient un "f" : xf0 est l'état futur de x0, Cmptf est l'état futur de Cmpt...

L'équation de sortie a été laissée après le if "clk'event" parce qu’elles sont toujours écrites à cette place dans les programmes présentés jusqu'à présent (voir description par graphe d'états dans un autre livre). Elle aurait pu être cependant ramenée dans la partie "calcul des états futurs"

Pour pouvoir faire des tests nous avons ajouté les sorties o0, o1 et o2. En principe, seul le compteur est une sortie puisqu’il s'agit d'une action.

Résultat de simulation

[modifier | modifier le wikicode]

Nous présentons maintenant un chronogramme réalisé à l'aide d'un outil de simulation VHDL :

Vous pouvez noter qu'effectivement le compteur passe à 3 quand on quitte l'étape 1. Facile aussi de remarquer que l'initialisation à 0 (du compteur) se fait elle aussi lorsque l’on quitte l'étape 0 (complètement à droite du chronogramme)

Deux actions différentes manipulent un même registre

[modifier | modifier le wikicode]

Imaginons que deux étapes (d'un GRAFCET) ou mieux, que deux états (d'un graphe d'états) réalisent une transformation différente d'un même registre. Ceux qui ont suivi jusqu'ici nous feront remarquer, à juste titre, que cette situation s'est déjà présentée dans le GRAFCET de la section précédente. Une étape réalisait tandis qu'une autre initialisait le compteur à 0. La solution a été présentée avec un mutiplexeur programmé avec un style "with select when" en VHDL.

Le compteur de passages montre une autre situation : une branche incrémente le compteur avec et l'autre décrémente avec . La gestion utiliserait elle aussi un multiplexeur.


Passons maintenant à la pratique

[modifier | modifier le wikicode]

Nous allons partir de notre calcul de PGCD pour mettre en pratique cette théorie.

Pour la petite histoire, l'exercice du PGCD a été donné comme Devoir Surveillé environ 4 fois ces douze dernières années à des étudiants par un des auteurs... et c’est seulement en mettant ses idées au clair avec la rédaction des deux sections précédentes qu’il lui est apparu que cet exemple est loin d’être optimisé. Aucun test n'est en effet réalisé tout de suite après une mise à jour de registre : il y a toujours un état qui suit la mise à jour et qui laisse le temps de faire le test. On se propose dans cette section de supprimer purement et simplement ces états d'attentes.

Une figure sera plus parlante :

Comparaison entre l'ancien et le nouveau séquenceur

Comme vous pouvez facilement le remarquer on est passé de huit à six états.

Voici donc le calcul du PGCD avec un programme unique qui gère le séquenceur et le chemin de données.

-- programme VHDL correspondant au calcul du PGCD
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all; -- WARP : use work.std_arith.all;
use ieee.std_logic_unsigned.all;
ENTITY pgcd2 IS 
PORT (Init,clk,Start : IN std_logic;
  oA,oB,oT : out std_logic_vector(7 downto 0)
);
END pgcd2;

ARCHITECTURE apgcd2 OF pgcd2 IS
-- les étapes proprement dit
SIGNAL x, xf : std_logic_vector(5 downto 0);
-- les registres
SIGNAL T,Tf, A, Af, B, Bf : std_logic_vector(7 downto 0);
SIGNAL Beq0,TinfB : std_logic;
BEGIN
  -- calcul des entrées combinatoires (les tests)
  -- on commence par Beq0
    with Bf select --oui c’est bien Bf !!!!
      Beq0 <= '1' when "00000000",
              '0' when others;
  -- on continue par TinfB
    process(Tf,B) begin
      if Tf<B then --oui c’est bien Tf !!!!
        TInfB <= '1';
      else
        TinfB <= '0';
      end if;
    end process;
  -- calcul des états futurs
    xf(0) <= Init;
    xf(1) <= (x(0) and not Beq0 and Start and not Init) or(x(4) and not Beq0 and not Init); 
    xf(2) <= (x(1) and not TinfB and not Init) or (x(2) and not TinfB and not Init);
    xf(3) <= (x(1) and TinfB and not Init) or (x(2) and TinfB and not Init);
    xf(4) <= x(3) and not Init;
    xf(5) <= (x(4) and Beq0 and not Init) or (x(0) and Beq0 and Start and not Init);
  PROCESS(clk) BEGIN
    IF (clk'event AND clk='1') THEN
-- équations de récurrences
      x <= xf;
  -- et aussi sur le même front :
      T <= Tf;
      A <= Af;
      B <= Bf;
    END IF;
  END PROCESS;
--équations de sorties ( le registre T)
  with x(2 downto 1) select
    Tf <= A when "01",
          T - B when "10",
          T when others;
-- le registre A
   with x(3 downto 0) select
    Af <= B when "1000",
          x"08" when "0001", --initialisation
          A when others;
-- le registre B
    with x(4 downto 0) select
    Bf <= T when "10000",
          x"06" when "00001",--initialisation
          B when others;
-- partie pour test bench
  oA <= A;
  oB <= B;
  oT <= T;
END apgcd2;

Voici maintenant le résultat d'une simulation :

qu’il n’est pas inutile de comparer à un autre chronogramme déjà donné mais reproduit encore une fois pour faciliter la comparaison :

On s'aperçoit que le résultat est obtenu au bout de 1250 ns dans la première simulation et au bout de 2050 ns dans la deuxième : le tout avec exactement la même horloge. La suppression de l'état 2 de l'ancien séquenceur permet de gagner en vitesse puisqu’il se trouvait dans une boucle. Il est facile de voir sur la simulation que cette boucle s'exécute deux fois plus vite maintenant.

Attention, les états ont été renumérotés dans le nouveau séquenceur pour que les numéros des "bit_vector" x et xf correspondent au dessin !!!


Liens internes

[modifier | modifier le wikicode]

Liens externes

[modifier | modifier le wikicode]