Objectifs du projet :
- Savoir comment calculer la factorielle de 0 ?
- Savoir comment maintenir les données en mémoire dans le bus de sortie ?
- Savoir comment synchroniser les données à l’entrée ?
- Savoir implémenter la fonction de saturation en VHDL
- Implémentation sur carte du projet
Analyse de fonctionnement
- Voir le projet : Projet électronique FPGA #7 : calcul de factorielle – n!
Comment calculer la factorielle de 0 ?
Dans ce projet on va s’intéresser aux aspects pratiques du code VHDL illustrés dans le projet 7. Comme vous constatez dans le projet 7, la factorielle de 0 n’est pas implémentée ! Je m’en suis rendu compte durant les tests sur carte du composant. Souvent en électronique, on fait des allers-retours entre l’étape de développement et implémentation pour but d’obtenir un fonctionnement optimal. En pratique, c’est rare que notre code marche au premier coup 🙂
Revenant à notre question, une solution possible est de tester la valeur de la donnée à l’entrer : Si elle est nulle on remplace la valeur nulle par 1 et on maintient la valeur dans le cas contraire.
if D_in=b"00000" then
D_in_tmp <= b"00001";
else
D_in_tmp<= D_in;
end if;
La donnée dans le bus de sortie D_out dure un coup d’horloge, la sortie passe à 1 dans le prochain coup d’horloge. D’une autre façon, le résultat dans le bus de sortie D_out bascule entre ‘1’ et D_in! (voir image ci-dessous) Ce fonctionnement peut être indésirable si on cherche une donnée stable tant que la donnée à l’entrée reste inchangée. L’avantage du fonctionnement mémoire est d’assurer que la donnée soit lisible et acquise correctement par le composant en amant.
L’implémentation de la fonction mémoire peut être réalisée à l’instant de la détection du front montant du signal D_outReady, dalleur ce dernier passe à 1 au même temps que la donnée soit présente dans le bus de sortie. L’approche consiste la mise à jour de la donnée de sortie uniquement durant le front montant du signal D_outReady.
Comme vous l’avez constaté, le bus de sortie est sur 123 bits pour une entrée sur 5 bits. Dans la partie implémentation on va s’intéresser uniquement par les 8 premiers bits du bus de sortie à cause de limitation de notre des LED dans notre kit de développement. Ce choix impose que la sortie D_out ne puisse prendre que des valeurs inférieures ou égales à 255 (1111 1111). D’une autre manière on ne peut calculer que les factorielles des valeurs suivantes : 0, 1, 2, 3 et 4. La factorielle de 6 != 720 >255. La fonction de saturation sera active pour des valeurs en entrée allant de 6 à 31. On a choisi 255 (FF) comme valeur de saturation. La figure ci-dessous illustre la fonction du transfert du composant menu de la fonction de saturation et le code Matlab correspondant:
Code matlab
clear all; close all; clc
% D_in
N=5;
D_in=0:2^N-1;
% D_out
D_out_tmp=factorial(D_in);
D_out=zeros(1,length(D_in));
for i=1:length(D_in)
if D_out_tmp(i)>=255
D_out(i)=255;
else
D_out(i)=D_out_tmp(i);
end;
end
% Affichage
figure(1);
plot(D_in,D_out); grid on; hold on
xlim([D_in(1) D_in(end)]);
ylim([D_out(1) D_out(end)+10]);
xlabel('D_{in}(1..31)');
ylabel('D_{out}(1..255)');
Extrait du code VHDL de la fonction de mémorisation et de saturation :
...
if D_outReady_tmp='1' then
if D_out_tmp > x"000000000000000000000000008" & b"00000" then -- 256
D_out <= x"FF";
else
D_out <= D_out_tmp(P-1 downto 0);
end if;
end if;
...
Code VHDL (FactorielMem.vhd):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity FactorielMem is
Generic ( N : positive := 108;
M : positive := 5;
P : positive := 8
);
Port ( Rst : in STD_LOGIC;
Clk : in STD_LOGIC;
D_in : in STD_LOGIC_VECTOR (M-1 downto 0);
D_out_Ready : out STD_LOGIC;
D_out : out STD_LOGIC_VECTOR (P-1 downto 0));
end FactorielMem;
architecture Behavioral of FactorielMem is
signal D_outReady_tmp : STD_LOGIC :='0';
signal D_out_tmp : STD_LOGIC_VECTOR (N+M-1 downto 0):=x"000000000000000000000000000" & b"00001";
signal D_in_tmp : STD_LOGIC_VECTOR (M-1 downto 0):=b"00001";
COMPONENT FactorielN
PORT(
Rst : IN std_logic;
Clk : IN std_logic;
D_in : IN std_logic_vector(M-1 downto 0);
D_out_Ready : OUT std_logic;
D_out : OUT std_logic_vector(N+M-1 downto 0)
);
END COMPONENT;
begin
FAC5: FactorielN PORT MAP(
Rst => Rst,
Clk => Clk,
D_in => D_in_tmp,
D_out_Ready => D_outReady_tmp,
D_out => D_out_tmp
);
-- Memorisation de la sortie + Gestion de 0!
P_data_out : process(Rst, Clk, D_outReady_tmp)
begin
if Rst ='1' then
D_out(P-1 downto 1) <=(others =>'0');
D_out(0) <= '1';
elsif Clk = '1' and Clk'event then
-- 0!=1
if D_in=b"00000" then
D_in_tmp <= b"00001";
else
D_in_tmp<= D_in;
end if;
-- Saturation de la sortie
if D_outReady_tmp='1' then
if D_out_tmp > x"000000000000000000000000008" & b"00000" then -- 256
D_out <= x"FF";
else
D_out <= D_out_tmp(P-1 downto 0);
end if;
end if;
end if;
end process;
D_out_Ready <=D_outReady_tmp;
end Behavioral;
Code VHDL du fichier de simulation (tb_FactorielMem.vhd):
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std;
ENTITY tb_FactorielMem IS
END tb_FactorielMem;
ARCHITECTURE behavior OF tb_FactorielMem IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT FactorielMem
PORT(
Rst : IN std_logic;
Clk : IN std_logic;
D_in : IN std_logic_vector(4 downto 0);
D_out_Ready : OUT std_logic;
D_out : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal Rst : std_logic := '1';
signal Clk : std_logic := '0';
signal D_in : std_logic_vector(4 downto 0) := b"00001";
--Outputs
signal D_out_Ready : std_logic;
signal D_out : std_logic_vector(7 downto 0);
-- Clock period definitions
constant Clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: FactorielMem PORT MAP (
Rst => Rst,
Clk => Clk,
D_in => D_in,
D_out_Ready => D_out_Ready,
D_out => D_out
);
-- Clock process definitions
Clk_process :process
begin
Clk <= '0';
wait for Clk_period/2;
Clk <= '1';
wait for Clk_period/2;
end process;
-- Rst process definitions
Rst_process :process
begin
Rst <= '1';
wait for Clk_period;
Rst <= '0';
wait for 200*Clk_period;
end process;
-- Input Data process definitions
D_in_process :process
begin
D_in <= D_in+1;
wait for 50*Clk_period;
end process;
END;
Résultats de simulation:
Pinout du composant (pinout_FactorielMem.ucf) :
# Alimentation
CONFIG VCCAUX = "3.3" ;
# Horloge 12 MHz
NET "Clk" LOC = P129 | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz;
# Entees: Rst + D_in
NET "Rst" LOC = P70 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_in[0]" LOC = P69 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_in[1]" LOC = P68 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_in[2]" LOC = P64 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_in[3]" LOC = P63 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_in[4]" LOC = P60 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
# Sortie D_out_Ready
NET "D_out_Ready" LOC = P19 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
# Sortie D_out
NET "D_out[0]" LOC = P46 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_out[1]" LOC = P47 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_out[2]" LOC = P48 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_out[3]" LOC = P49 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_out[4]" LOC = P50 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_out[5]" LOC = P51 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_out[6]" LOC = P54 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "D_out[7]" LOC = P55 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
Photos du projet:
[masterslider id= »6″]
Vidéo illustrative:
************
Un petit commentaire de vous, un Grand encouragement pour nous ![?](https://s.w.org/images/core/emoji/11/svg/1f642.svg)
************
Téléchargement du projet
************
Une réponse sur « Projet électronique FPGA #9 : Calcul de la factorielle de n: Implémentation sur carte FPGA »
[…] PROJET #9 : CALCUL DE LA FACTORIELLE DE N: IMPLÉMENTATION SUR CARTE FPGA […]