Ghdl 1
9 Mai 2015

Le compteur

Le compteur est une unité logique qui effectue une opération de comptage de 0 à 2N-1, avec N correspondant au nombre de bits souhaités. Le principe est simple, à chaque coup d'horloge le compteur incrémente sa valeur d'une unité passant ainsi de 0 à 1,de 1 à 2 ainsi de suite jusqu'à atteindre 2N-1, puis redémarre à 0. Le compteur dispose généralement de deux entrées : Reset: le signal de reset,clk: l'horloge et d'une sortie de donnée Data. L'opération de comptage n'est active que si l'entrée Reset du compteur est à 0, dans le cas contraire la valeur du compteur est remise à 0. On constate aussi que le compteur est sensible à l'horloge, ce qui signifie qu'il s'agit d'un composant séquentiel. Cette petite présentation, nous permet déjà d'écrire la description de notre circuit en VHDL suivante :

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

entity compteurNbit is
	-- Le mot clé générique nous permet de spécifier à la fois une 
	-- valeur par défaut à N, mais aussi de rendre notre unité
	-- paramétrable.
	generic (N 		: integer := 4);
	port(	clk		: in STD_LOGIC;
			reset	: in STD_LOGIC;
	     	data	: out STD_LOGIC_VECTOR (N-1 downto 0)
	     );
end;


architecture a_compteurNbit of compteurNbit is

-- signal interne servant au comptage
signal Sdata : UNSIGNED(N-1 downto 0);

begin
	process(clk,reset) begin
		if reset='1' then
			Sdata <= (OTHERS => '0') ;
		elsif rising_edge(clk) then
			Sdata <= Sdata + 1;
		end if;
	end process;
	data <= std_logic_vector(Sdata);
end a_compteurNbit;

							

J'en ai profité pour faire directement un compteur paramétrable; en effet grace au mot clé generic on peut instancier son composant avec la valeur de N que l'on souhaite. De plus l'utilisation du signal interne de type unsigned est obligatoire compte tenu de la version de VHDL utilisée par GHDL. En effet la sortie data ne peut pas être directement relu ce qui nous impose d'utiliser un signal interne avec lequel on va effectuer l'opération et recopier ce dernier dans data. De plus le type std_logic_vector ne nous permettant pas d'effectuer des opérations d'addition, passer par un signal interne de type unsigned est donc à priori indispensable. Ceci dit j'ai vu qu'avec la version VHDL 2008 il était possible d'effectuer des opérations d'incrémentation avec des std_logic_vector, mais bon on peut se contenter de la description dans son état actuel.

Le testeur

Nous avons donc élaboré la description de notre compteur, attaquons nous désormais au testeur. Notre testeur va effectuer deux traitements. Le premier est celui de la génération de l'horloge dont le circuit a besoin. Le second est celui d'instancier un composant compteur et de modifier ses entrées afin de voir l'impact sur son comportement via la valeur de la sortie Data. Chaque traitement sera réalisé par un processus comme le montre la description du testeur suivante :

								library IEEE;
use IEEE.STD_LOGIC_1164.all;

entity compteurNbitTB is
end compteurNbitTB;

architecture compteurNbitTB_behavior of compteurNbitTB is
	component compteurNbit
		generic (N 		: integer := 4);
		port(	clk		: in STD_LOGIC;
				reset	: in STD_LOGIC;
	     		data	: out STD_LOGIC_VECTOR(N-1 downto 0)
	     	);
	end component;

	for compteurNbit_unit: compteurNbit use entity work.compteurNbit;
	
	-- Signaux de test / récupération de données
	signal Sreset : STD_LOGIC := '1';
	signal Sclk : STD_LOGIC := '1';
	signal Sdata : STD_LOGIC_VECTOR(3 downto 0);
	
	-- Constante définissant le nombre de cycle
	constant CNBCycle : integer := 100;
begin
	compteurNbit_unit: compteurNbit 
		generic map (N  => 4)
		port map (reset => Sreset,
				  data  => Sdata,
                  clk   => Sclk
                  );
    -- Processus dédié à la génération de l'horloge
	clk_process : process
	begin
		for i in 1 to CNBCycle loop
			Sclk <= not Sclk;
			wait for 5 ns;
			Sclk <= not Sclk;
		end loop;
		wait;
	end process clk_process;
	
	-- Processus de test du composant
	main_process : process
		begin
			-- comptage normal
			Sreset <= '0';
			wait for 80 ns;
			-- arrêt du processus de comptage
			Sreset <= '1';
			wait for 10 ns;
			-- reprise du comptage
			Sreset <= '0';
			wait for 40 ns;
			-- fin du test 
			assert false report "end of test" severity note;
			wait;
	end process;
end compteurNbitTB_behavior;

								

A noter qu'un testeur n'est pas synthétisable. Ainsi on a le droit d'inclure diverses notions tels les temps d'attente et même d'afficher du texte si on le souhaite. Une fois le composant et son testeur correctement édité on va procéder à la phase suivante qui consiste à exécuter notre testeur et à observer le chronogramme obtenu.

Le test

La première chose à faire lorsqu'on a édité son circuit et son testeur est de vérifier et de générer le fichier objet correspondant à ces deux composants (le testeur étant aussi un composant même s'il ne peut être synthétisé). Pour cela nous allons utiliser ghdl. Ghdl s'utilise en ligne de commande sur un système Linux / Mac OS X. Voici les trois commandes que nous allons utiliser :

										ghdl -a monComposant.vhdl

									

exécutée avec l'option a, ghdl permet d'analyser notre description, puis si elle est correcte de générer un fichier objet correspondant. Si la description n'est pas correcte une erreur sera indiquée.

										ghdl -e monComposant

									

l'option e, permet d'élaborer notre composant et donc de produire une version logicielle de notre composant, qui peut être utilisée pour les tests ou exécutée s'il s'agit d'un testeur.

										ghdl -r monComposantTB --vcd=monComposantTB.vcd

									

la commande précédente, permet d'exécuter notre testeur et d'enregistrer les signaux du composant testé afin de produire le chronogramme dont le fichier correspondant sera celui indiqué par l'option --vcd. Ainsi dans notre cas, nous allons d'abord élaborer notre composant :

								    	ghdl -a compteurNbits.vhdl
								    	ghdl -e compteurNbit

									

Puis le testeur :

										ghdl -a compteurNbitsTB.vhdl
										ghdl -e compteurNbitTB
										
									

Et enfin exécuter notre testeur : ghdl -r compteurNbitTB --vcd=compteurNbitTB.vcd. Une fois cette dernière commande exécutée l'on devrait obtenir un nouveau fichier dans notre répertoire de travail compteurNbitTB.vcd. Ce fichier peut être ouvert avec GTKwave. Une fois le fichier ouvert il apparait dans l'onglet en bas à gauche les trois signaux sclk,sdata et sreset qui sont les signaux de notre testeur. On sélectionnant puis en déposant (le fameux drag and drop) chacun des signaux dans l'onglet Signals on voit apparaître les traces de notre chronogramme. Après avoir remis l'axe des abscisse à une échelle raisonnable (nanoseconde) on peut voir le comportement de notre circuit. Qui compte lorsque le Reset est à 0, ne compte pas lorsque le Reset est à 1, et surtout qui reprend l'opération après avoir atteint sa valeur finale. On peut donc dire que notre compteur fonctionne bien et on peut donc le mettre parmis les composants testés et validés.


Voilà c'est terminé pour ce premier composant. Pour le prochain billet on montera encore d'un cran avec un automate à états finis. J'espère n'avoir pas été trop long, auquel cas faites le moi savoir afin que je rectifie le tir le plus tôt possible.

9 Mai 2015, Boris.

PS : Les sources sont disponibles sur mon github.
PS++ : J'ai mis à jour le billet en rajoutant la coloration syntaxique pour les codes sources. Et en modifiant l'image associée au billet (moins austère que la précédente). A César ce qui est à César : SyntaxHighlighter.

 
comments powered by Disqus

Sites amis

Copyright(c) bignumb 2014