Beruflich Dokumente
Kultur Dokumente
net/publication/329220722
CITATIONS READS
0 492
1 author:
Ridha Ghayoula
University of Tunis El Manar
69 PUBLICATIONS 172 CITATIONS
SEE PROFILE
Some of the authors of this publication are also working on these related projects:
All content following this page was uploaded by Ridha Ghayoula on 27 November 2018.
UNIVERSITE TUNIS EL
MANAR
Maître de conférences
Chapitre 4 VERILOG 59
4.1. Introduction .......................................................................................................................... 60
4.2. Verilog ................................................................................................................................... 60
4.2.2. Valeurs Logiques ..................................................................................................................... 62
4.2.4. Codage des nombres entiers ................................................................................................. 67
4.2.6. Expressions et opérateurs ...................................................................................................... 70
4.2.7. Calcul des expressions : taille et type ................................................................................... 74
4.2.8. Directives de compilation ...................................................................................................... 78
1. Objectifs ..................................................................................................................................113
2. Description de la carte FPGA XILINX Kintex-7 FPGA KC705 Evaluation Kit.....................113
3. Description de la méthodologie de conception ......................................................................116
Lab 0: Synthèse avec le logiciel Xilinx ISE design Tools 14.6 ...................................................118
Lab 1: Modélisation d’un décodeur hexadécimal pour affichage à 7 segments ....................... 136
Lab 2: Modélisation d’un Compteur/Décompteur ................................................................... 140
Lab 3: Modélisation d’un Additionneur .................................................................................... 142
Lab 4: Modélisation d’un Transcodeur ..................................................................................... 144
Lab 5: Mémoire ROM ............................................................................................................... 146
Lab 6: Mémoire RAM ................................................................................................................ 153
Lab 7: Artix-7 ............................................................................................................................. 156
Lab 8: Hello World avec Verilog & Vivado ............................................................................... 163
Lab 9: Implémentation d'un Compteur avec Artix-7 ................................................................ 170
Lab 10: Implémentation Arty Pmod VGA ................................................................................. 179
ANNEXES .................................................................................................................................181
ANNEXE 1: Master UCF Listing KC705 Board UCF Listing ..................................................181
ANNEXE 2: XDC file Artix-7 .................................................................................................. 186
Les Références Bibliographiques .............................................................................................. 190
1.1. Introduction
L’évolution de l’industrie des circuits intégrés durant la dernière décennie a été tellement rapide
qu’il est maintenant possible d’intégrer plusieurs systèmes complexes sur une seule puce. Cette
évolution vers des niveaux d’intégration de plus en plus élevés est motivée par les besoins de
systèmes plus performants, légers, compacts et consommant un minimum de puissance. Dans de
telles circonstances, la gestion de la complexité avec les outils d’aide à la conception traditionnels
(les outils de bas niveau : masque, schématique…) devient une tâche pénible, coûteuse, voire
impossible, quand on considère les contraintes de mise en marché d’un produit. Dans le but de
mieux gérer la complexité des circuits intégrés, tout en gardant les coûts du développement dans
des limites raisonnables, d’autres outils d’aide à la conception, dits outils de synthèse, ont vu le
jour dès le début des années 1990. En effet, le but ultime de ces outils associés avec un langage de
conception et de simulation puissant, tel que le langage VHDL, est de générer le dessin des
masques d’un circuit à partir de sa description comportementale de haut niveau. Ainsi, le
concepteur peut se limiter à la conception, à la modélisation et à la simulation de son produit,
sans tenir compte des détails de mise en œuvre au niveau schématique ou du dessin des masques.
L’abréviation VHDL signifie VHSIC Hardware Description Language (VHSIC : Very High
Speed Integrated Circuit). Ce langage a été écrit dans les années 70 pour réaliser la simulation de
circuits électroniques. On l’a ensuite étendu en lui rajoutant des extensions pour permettre la
conception (synthèse) de circuits logiques programmables (P.L.D. Programmable Logic Device).
Auparavant pour décrire le fonctionnement d’un circuit électronique programmable les
techniciens et les ingénieurs utilisaient des langages de bas niveau (ABEL, PALASM,
ORCAD/PLD,..) ou plus simplement un outil de saisie de schémas.
Actuellement la densité de fonctions logiques (portes et bascules) intégrée dans les PLDs est telle
(plusieurs milliers de portes voire millions de portes) qu’il n’est plus possible d’utiliser les outils
d’hier pour développer les circuits d’aujourd’hui.
Les sociétés de développement et les ingénieurs ont voulu s’affranchir des contraintes
technologiques des circuits. Ils ont donc créé des langages dits de haut niveau à savoir VHDL et
VERILOG. Ces deux langages font abstraction des contraintes technologies des circuits PLDs.
Ils permettent au code écrit d’être portable, c’est à dire qu’une description écrite pour un circuit
peut être facilement utilisée pour un autre circuit.
S1
Les S2 Les
Entrees Sorties
S3
Library IEEE ;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
D
Bascule_D
RESET
Entity bascule is
Port ( CLOCK : in std_logic;
D : in std_logic;
RESET : in std_logic;
Q : out std_logic );
End bascule;
Remarque : Après la dernière définition de signal de l’instruction port il ne faut jamais mettre de
point virgule.
Le nom du signal est composé de caractères : les premier caractère est une lettre, VHDL
n'est pas sensible à la casse (t/T)
Le sens du signal :
o in = signal d'entrée
o out = signal de sortie
o inout : signal en entrée/sortie
le type du signal : les types prédéfinis par le langage VHDL sont assez nombreux et le
langage permet la création de ses propres types ou sous types. Pour le moment, on va
utiliser std_logic pour un signal et std_logic_vector pour un bus.
Constantes: Les constantes sont utilisées pour référencer une valeur ou un type spécifique.
Elles permettent une meilleur lecture et maintenance d'une source. De tous types, elles sont
utilisées dans les entités, architectures ou packets.
Syntaxe
Syntaxe
ENTITY entity_name IS
[generic_declarations]
[port_declarations]
END [entity_name];
Exemple N°3 :
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY nor2 IS
L’instruction port .
Syntaxe: NOM_DU_SIGNAL : sens type;
Exemple: CLOCK: in std_logic;
BUS : out std_logic_vector (7 downto 0);
On doit définir pour chaque signal : le NOM_DU_SIGNAL, le sens et le type.
In Out
D inout
Exemple
RESET buffer
1.2.2.3. Le TYPE.
Le TYPE utilisé pour les signaux d’entrées/sorties est :
- le std_logic pour un signal.
- le std_logic_vector pour un bus composé de plusieurs signaux.
Par exemple un bus bidirectionnel de 5 bits s’écrira :
LATCH : inout std_logic_vector (4 downto 0) ;
Où LATCH(4) correspond au MSB et LATCH(0) correspond au LSB.
b) Conversions de type
Les environnements de développement fournissent en général des paquetages comportant des
fonctions de conversion de type. Par exemple, la bibliothèque de Xilinx ISE
contient :
- conv_integer (a) pour convertir un std_logic_vector a en un integer
- conv_unsigned (x,n) pour convertir un std_logic_vect or, integer, unsigned ou signed x
en un unsigned de n bits (réalise un changement de taille)
- conv_signed (x,n) pour convertir un std_logic_vector, integer, signed ou unsigned x en
un signed de n bits (réalise un changement de taille)
- conv_std_logic_vector (x,n) pour convertir un integer, unsigned ou signed x en un
std_logic_vector de n bits
Pour utiliser ces fonctions, il suffit d’accéder au paquetage std_logic_arith de la bibliothèque ieee
1.2.2.4.Les identificateurs
Les identificateurs sont des appellations d’objets du langage (données et types).
- Ils sont constitués de caractères alphabétiques (26 lettres), numériques (10 chiffres
décimaux) et du caractère souligné _ ; les lettres accentuées sont exclues
- Le premier caractère doit être une lettre
- Les lettres majuscules et minuscules sont équivalentes
- Le dernier caractère doit être différent de _
- Deux _ à la file sont interdits
- Le nom ne doit pas être un mot réservé
- La longueur d’un mot est quelconque (mais une ligne maximum)
1.2.2.5.Les littéraux
Les littéraux sont les représentations de valeurs attribuées aux objets données et aux objets types.
- Les entiers décimaux : 1234
- Les bits ‘0’, ‘1’ -- type bit
Flot de données : on écrit explicitement les fonctions booléennes que l'on veut voir
implémentées (à réserver aux plus petits circuits pour des raisons de lisibilité) ; c'est lui
qu'on a utilisé pour implémenter le demi-additionneur ;
Structurel : on décrit le circuit comme une série de boîtes noires interconnectées au
moyen de signaux (utilisé pour des circuits moyens ou grands) ; on procèdera de cette
manière pour synthétiser un additionneur complet à l'aide de deux demi-additionneurs ;
Comportemental: de manière très semblable à un langage de programmation
informatique, on précise le fonctionnement voulu à l'aide d'une suite d'instructions de
contrôles plus ou moins évoluées (conditions, boucles, etc.), dans un process
L’architecture établit à travers les instructions les relations entre les entrées et les sorties. On peut
avoir un fonctionnement purement combinatoire, séquentiel voire les deux séquentiel et
combinatoire.
Entity S
b (AND)
- Pour les signaux composés de plusieurs bits on utilise les guillemets " … " , voir les exemples ci
dessous :
- Les bases numériques utilisées pour les bus peuvent être :
BINAIRE, exemple : BUS <= "1001" ; -- BUS = 9 en décimal
HEXA, exemple : BUS <= X"9" ; -- BUS = 9 en décimal
OCTAL, exemple : BUS <= O"11" ; -- BUS = 9 en décimal
Opérateur VHDL
ADDITION +
SOUSTRACTION -
MULTIPLICATION *
DIVISION /
Remarque : l'utilisation de ces opérateurs avec des signaux de grandes tailles peut générer de
grandes structures électronique.
Exemple N°1 :
S1 <= A – 3 ; -- S1 = A – 3
-- On soustrait 3 à la valeur de l’entrée / signal A
S1 <= S1 + 1 ; -- On incrémente de 1 le signal S1
Remarque : Un commentaire débute par deux traits (signe moins) : --
SEL[1..0]
Library ieee;
USE iee.std_logic_1164.all;
Entity multiplex is
Port ( E1,E2,E3,E4 : in std_logic;
SEL : in std_logic_vector (1 downto 0);
S : out std_logic );
End multiplex;
Architecture desc_multiplex of multiplex is
Begin
S <= E1 when SEL = "00"
Else E2 when SEL = "01"
Else E3 when SEL = "10"
Else E4;
End desc_multiplex;
Exemple N°1 : Réaliser le programme d'un multiplexeur 1 vers 4 avec entrée de sélection SEL et
sortie de validation Enable active sur l'état bas.
SEL S
S1 00 S1
E S2 01 S2
DEMX 10 S3
S3 11 S4
S4
en
SEL[1..0]
Library ieee;
USE iee.std_logic_1164.all;
Entity demultiplex is
Port ( SEL : in std_logic_vector (1 downto 0);
E : in std_logic
Enable : in std_logic;
S1,S2,S3,S4 : out std_logic;);
End demultiplex;
1.2.6. Les instructions du mode séquentiel
1.2.6.1. Définition d'un process
Un process est une partie de la description d'un circuit dans laquelle les instructions sont
exécutées séquentiellement. L'exécution d'un process est déclenché par un ou des changements
d'états de signaux logiques. Le nom de ces signaux est défini dans la liste de sensibilité lors de la
déclaration du process.
[nom_du_process :] Process ( liste_de_sensibilite )
Begin
… instruction_du_process … ;
End process;
Le nom du process est facultatif.
1.2.6.2. Règle de fonctionnement d'un process
A) L'exécution d'un process
L'exécution d'un process a lieu à chaque changement d'état d'un signal de la liste de
sensibilité
Page | 13 © ISI 2013 Ridha Ghayoula
L'instruction du process s'exécute séquentiellement
Les changements d'état des signaux par les instructions du process sont prises en compte
à la fin du process
2 process d'une architecture ayant la même liste de sensibilité vont être exécutés en même
temps
Exemple N°1 :
Process (C,D)
Begin
A <= 2 ;
B <= A + C ;
A <= D + 1 ;
E <= A * 2 ;
End process;
A=1 A <= D + 1 ;
B=1 B <= A + C ;
C=1
D=1
E=1 E <= A * 2 ;
On commence en mettant D à 2
On trouve les résultats suivants :
A=3 B=2 E=2
D
Bascule_D
RESET
library ieee;
use ieee.std_logic_1164.all;
ENTITY Bascule_D IS
PORT ( D : IN STD_LOGIC;
clk : IN STD_LOGIC;
Q : OUT STD_LOGIC);
END Bascule_D;
Remarques:
- Seul le signal CLK fait partie de la liste de sensibilité. D’après les règles de fonctionnement
énoncées précédemment, seul un changement d’état du signal CLK va déclencher le process
et par conséquent évaluer les instructions de celui-ci.
- L’instruction if (CLK'event and CLK='1') then permet de détecter un front montant du
signal CLK. La détection de front est réalisée par l’attribut event appliqué à l’horloge CLK. Si on
veut un déclenchement sur un front descendant, il faut écrire l’instruction suivante : if
(CLK'event and CLK='0').
- Les bibliothèques IEEE possèdent deux instructions permettant de détecter les fronts montants
) rising_edge(CLK) ou descendants falling_edge(CLK).
- Si la condition est remplie alors le signal de sortie S sera affecté avec la valeur du signal d’entrée
D.
B) Les principales structures du mode séquentiel
A l'intérieur d'un process, on peut utiliser des "if" et/ou des "case". L'exécution est alors
séquentielle.
De même on peut utiliser des boucles pour contrôler l'exécution. Les "for" sont à bornes
fixes, alors que les "while" ne le sont pas.
E1
S
MUX
EN
sel
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY mux IS
PORT (E1,E2,sel : IN std_logic;
S : OUT std_logic);
END mux;
ARCHITECTURE behavior OF mux IS
BEGIN
PROCESS (sel,E1,E2) -- liste de sensibilité
BEGIN
IF sel = '0' THEN -- test si sel vaut 0
S <= E1;
ELSIF sel = '1' THEN -- test si sel vaut 1
S<= E2;
ELSE
y <= 'X'; -- si sel n'est ni à 1 ni à 0, on affecte X à S
END IF;
END PROCESS;
END behavior;
S1
E S2
DEMX
S3
S4
en
SEL[1..0]
Library ieee;
USE ieee.std_logic_1164.all;
Entity demultiplex is
Port ( SEL : in std_logic_vector (1 downto 0);
E : in std_logic
Exemple N°2 :
process (A)
begin
Z <= "0000";
for I in o to 3 loop
if (A = I) then
AFTER spécifie un temps de réponse d'un signal par rapport à son événement.
Deux modes de délai sont possibles INERTIAL (défaut) ou TRANSPORT. Le mode
INERTIAL ne propage pas les impulsions plus courtes que le temps de propagation.
Syntaxe :
sigal_name <= [INERTIAL/TRANSPORT] expression AFTER time_expression
Exemple N°1 : propage pas les impulsions plus courtes que le temps de propagation.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity porte_and is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
z : out STD_LOGIC);
end porte_and;
architecture Behavioral of porte_and is
begin
PROCESS(a,b)
BEGIN
z <= a and b AFTER 10 ns; -- temps de propagation est de 10ns
END PROCESS ;
end Behavioral;
CLK
Q
SENS
RAZ
CMP_DEC /
4 bits
Exercice 2 : boite
On considère le circuit ‘boite’ décrit par sa table de vérité suivante :
Inputs Outputs
A B RAZ CLK Q
X X 1 0
0 0 0 Pas de changement
0 1 0 0
1 0 0 1
1 1 0 Haute impédance
d
gfedcba
BCH[3..0] SEG[6..0]
1°) Etablir la table de vérité de la fonction. (Donner la valeur HEXA du mot de sortie).
ENTREES SORTIES Hexa
BCH(3) BCH(2) BCH(1) BCH(0) SEG(6) SEG(5) SEG(4) SEG(3) SEG(2) SEG(1) SEG(0)
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1
2°) Donner le code VHDL de l’entité correspondante de ce décodeur Dec_Adress.
3°) Donner le code VHDL de l’architecture correspondante.
Transcodeur
S2 S 1 S0
2 bits
IL E IR
S1..0
REGISTRE
H
Q
4 bits
Donnez l’entité et l’architecture décrivant l’interface du circuit. Les signaux d’entrée E et de sortie
Q seront considérés comme des std_logic_vector, avec un nombre de bits N paramétrable (N=4
bits). S sera également de type std_logic_vector. Le reste des signaux sera de type std_logic.
CS_A
8 bits
CS_B
Dec_Adress
Adresse CS_C
CLK
CPTR Carry
CLK
bascule D
CLK RESET
1°) Ecrire un code VHDL pour d’une bascule D avec remise a zéro.
2°) Même exemple que précédemment mais avec des entrées de présélections de mise à zéro
RESET prioritaire sur l’entrée de mise à un SET, toutes les deux sont synchrones de l’horloge
CLK.
3°) Même exemple que précédemment mais avec des entrées de présélections, de mise à zéro
RESET prioritaire sur l’entrée de mise à un SET, toutes les deux sont asynchrones de l’horloge
CLK.
CMPL
CLK
RESET
2.1. Introduction
Modèle comportemental :
description du fonctionnement du système :
- algorithmes, machine d’états
algorithme proche de ceux des langages de programmation
le temps peut intervenir :
- permet de coller à la réalité par le respect des temps de traversée
une description haut niveau est d’abord comportementale :
- elle sert de référence pour la suite de la conception
A
S
MUX2-1
B
sel
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Mux21_comportementale is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
Sel : in STD_LOGIC;
S : out STD_LOGIC);
end Mux21_comportementale;
architecture Behavioral of Mux21_comportementale is
process (A, B, S)
begin
S <= A WHEN (Sel='0') else
B WHEN (Sel='1') else
'X';
End process;
end Behavioral;
library ieee;
use ieee.std_logic_1164.all;
entity MUX is
port(
E0, E1, E2, E3: in std_logic;
SEL: in std_logic_vector(1 downto 0);
S: out std_logic);
End MUX;
architecture CMP of MUX is
begin
process (E0, E1, E2, E3, SEL)
begin
if SEL="00" then
S <= E0;
elsif SEL="01" then
S <= E1;
elsif SEL="10" then
S <= E2;
elsif SEL="11" then
S <= E3;
Else S <= '-';
end if;
end process;
end FLOT_MUX;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Additionneur_FD is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
Cin : in STD_LOGIC;
S : out STD_LOGIC;
Cout : out STD_LOGIC);
end Additionneur_FD;
architecture Behavioral of Additionneur_FD is
begin
S<= A xor B xor Cin;
Cout<= (A and B) or (Cin and (A or B));
end Behavioral;
A
S
MUX2-1
B
sel
S= NOT(Sel). A + Sel .B
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Mux21_FD is
Port ( A : in STD_LOGIC;
B : in STD_LOGIC;
Sel : in STD_LOGIC;
S : out STD_LOGIC);
end Mux21_FD;
architecture Behavioral of Mux21_FD is
begin
La configuration est une unité de compilation optionnelle, très utile pour les gros
circuits. Par exemple pour accélérer la simulation , un même composant peut être associé
à un couple entité/architecture détaillé et synthétisable ou un autre couple plus abstrait et
plus rapide à simuler. Pour ne pas utiliser de configuration, une règle fréquente est
d'utiliser le même nom pour le composant et l'entité associée, c'est le cas pour ModelSim
et les outils de synthèse FPGA.
La description structurelle est nécessaire pour simuler un circuit dont les vecteurs stimulis sont
eux mêmes issus d'un modèle VHDL. Le modèle de plus haut niveau fait donc appel au circuit à
tester (Device Under Test) et d'un générateur de stimulis. Ces deux objets sont instanciés dans un
même circuit, généralement appelé "testbench" (mais ce n'est pas une obligation) qui est
autonome : il n'aura pas d'entrées ni de sorties.
Instanciation :
L'instanciation d'un composant se fait dans le corps de l'architecture de cette façon :
<NOM_INSTANCE>:<NOM_COMPOSANT> port map (LISTE DES CONNEXIONS);
Exemple N°2
Dans cet exemple , 2 instances de composant "and2" sont appelées pour créer une porte ET à 3
entrées.
L'association des ports du composants aux signaux de l'instance se fait à l'aide de la clause port
map.
La syntaxe des associations est soit
1. par nom où chaque broche du composant est associée à un signal : cas de inst_1
2. positionnelle où l'ordre des signaux correspond à l'ordre des broches : cas de inst_2
Exemple N°1 :
entity AND_3 is
port(
e1 : in std_logic;
e2 : in std_logic;
e3 : in std_logic;
s : out std_logic);
end AND_3;
architecture arc of AND_3 is
-- signal z : bit;
component and2
port (
a : std_logic;
b : std_logic;
s : std_logic);
end component;
begin
inst1 : and2 port map (a=>e1, b=>e2 , s=>z);
inst2 : and2 port map (z, e3, s);
end arc;
COMPONENT 1
A S
XOR
B
AND Cout
HA
A B
Cout Cin
FA
Si on pose X A B et Y A.B
On obtient : Cout Y T et S Z
On remarque que X et Y sont les sorties d’un demi additionneur (HF) ayant comme
entrées A et B
On remarque que Z et T sont les sorties d’un demi additionneur (HF) ayant comme
entrées X et Cin
Z
Cin
HA S
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY OR_2 IS
PORT(a,b: IN std_logic;
c: OUT std_logic);
END OR_2;
ARCHITECTURE beh OF OR_2 IS
Begin
c <= a OR b;
end beh;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY full_adder IS
PORT(in1,in2,cin: IN std_logic;
result,carry: OUT std_logic);
END full_adder;
Exemple N°2 : L'exemple classique de l'additionneur n bits... On utilise ici une boucle FOR
GENERATE pour instancier automatiquement les différentes primitives ainsi que les noeuds les
connectant entre elles. Notez qu'il n'est pas nécessaire de déclarer la variable de boucle mais que
l'instruction FOR GENERATE nécessite une étiquette.
component FA
port( A, B, Cin : in std_logic;
S, Cout : out std_logic);
end component;
Exercice 1 : Compteur
Le comportement de cette fonction (compteur) peut être décrit comme étant la mise en cascade
d’un additionneur et un registre à chargement parallèle (8 bits).
[7:0] Q[7:0]
[7:0] D[7:0] Q[7:0]
+ Registre
1
8 bits
H
Reset
4°) donner un code VHDL d’une porte NAND simple à deux entrées.
5°) Déduire une description de type structurelle de ce circuit (les entrées : A, B, Sortie : S)
Exercice 2: Additionneur
On désire modéliser un additionneur sur 1 bit (FA) gérant les problèmes de retenue. Ai et Bi
sont les entrées de 1 bit chacune à additionner, Cin est une retenue en entrée, Si est le résultat et
Cout la retenue de sortie
Ai Bi
Cout Cin
FA
Si
1°) Additionneur
a) Ecrire les équations des sorties Si et Cout (en utilisant des portes AND, OR et XOR).
Cout i3 i2 i1 Cin
FA FA FA FA
d) Comme pour l'additionneur, un soustracteur peut être réalisé en cascadant les cellules de
base.
Ecrire un programme en VHDL avec une description structurelle pour ce soustracteur
(en utilisant les fils internes i1, i2, i3, b0, b1, b2 et b3).
B(3) B(2) B(1) B(0)
Cout i3 i2 i1 ‘1’
FA FA FA FA
2°) Pour obtenir un Additionneur Soustracteur (à N-bit), il suffit d’enchaîner ‘N’ Additionneur
Complet (à 1-bit) en série + NXORs.
Par exemple, pour N=4: Ecrire un code VHDL pour ce circuit en utilisant une description de
type structurelle.
Add_soust=C0
XOR XOR
A(3) A(2) A(1) XOR
A(0) XOR
b3 b2 b1 b0
C4 c3 c2 c1
FA FA FA FA
A(3) B(1) A(3) B(0) A(2) B(1) A(2) B(0) A(1) B(1) A(1) B(0) A(0) B(1) A(0) B(0)
'0'
c7 c6 c5 c4 c3 c2 c1
'0'
FA FA FA FA
'0'
FA FA FA FA
'0'
FA FA FA FA
P7 P6
P5 P4 P3 P2 P1 P0
Exercice 3 : Multiplexeur
Partie I :
Le schéma bloc du multiplexeur à deux entrées est illustré par la figure ci-dessous
E(0)
S
MUX2-1
E(1)
)
sel
E(0)
E(1) S
MUX2-1
E(2)
E(3)
)
sel(1) sel(0)
3°) Utiliser une description de type flot de données pour réaliser un additionneur de 1 bit dont le
schéma bloc est illustré par la figure suivante.
INH
Le compteur est un compteur 3 bits modulo 8. Le fonctionnement de ce circuit est donné par la
table de vérité suivante :
Inputs Outputs
Sens H Q(2) Q(1) Q(0)
1 Incrémentation
0 Décrémentation
Réponse:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity GEN_ADD is
generic ( n: postive :=8);
port ( A : in unsigned(n-1 downto 0);
B : in unsigned(n-1 downto 0);
S : out unsigned(n-1 downto 0));
end GEN_ADD;
architecture RTL of GEN_ADD is
begin
S <= A + B;
end RTL;
D0...D7
A0...A19
A0
Décodeur
(1/4) A1
A(n-1) D(m-1)
A(1)
A(0) RAM D(1)
D(0)
CE
WE
CE WE Opération
0 x None
Read from memory location
1 0
selected by address lines
Write to memory location selected
1 1
by address lines
Réponse:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity memory is
Port ( CE : in STD_LOGIC;
WR : in STD_LOGIC;
A : in STD_LOGIC_VECTOR (19 downto 0);
D : BUFFER STD_LOGIC_VECTOR (7 downto 0));
end memory;
3.1. Introduction
Une machine à états finis (Finite State Machine FSM) est une machine séquentielle caractérisée
par :
un vecteur d’entrée.
un vecteur de sortie.
une séquence d’états définissant son comportement.
- La machine (également appelée automate ou séquenceur) va passer d’un état à l’autre
suivant les séquences d’entrée qu’elle reçoit. On attribue généralement à la machine un
état de départ lui permettant de débuter son fonctionnement à partir d’un point fixe.
Exemples :
- le programmateur de machine à laver : suite à la mise en marche, le programmateur
contrôle que la porte est fermée, si oui il commande l’ouverture de la vanne d’arrivée de
l’eau, quand la machine est pleine, il va actionner le tambour, etc.
- Distributeur automatique de monnaie
- Feu de circulation pour piéton
- La partie contrôle d’un processeur
3.2. Représentation
Les machines à états finis sont généralement représentées par des diagrammes d’états
permettant de visualiser les transitions entre les états. Les états sont alors représentés par des
cercles avec leur nom inscrit à l’intérieur ; les transitions entre les états sont représentées par des
arcs dirigés reliant les cercles. Les conditions (valeurs du vecteur d’entrée) enclenchant ces
transitions sont notées sur les arcs et finalement la valeur des sorties est généralement indiquée
soit sur l’arc (séparée des entrées par un trait oblique : /) ou à l’intérieur du cercle (séparée du
nom de l’état par un trait oblique : /).
- Exemple de machine à états finis où les sorties sont indiquées à l’intérieur des cercles :
Etat 0 Etat 2
Etat 1 S<='1'
S<='0'
S<='0'
E='0'
Depart
E='0'
On trouve les éléments suivants :
• trois états : Etat 0, Etat 1 et Etat 2.
• un état de départ Etat 0.
• une entrée dont la valeur est notée sur les arcs.
• une sortie dont la valeur est associée à chaque état, respectivement 0 pour Etat 0, 0 pour
Etat 1 et 1 pour Etat 2.
• Cette machine permet de détecter une séquence de deux "1" consécutifs en entrée.
• Le concepteur qui propose cette machine n’avait au départ qu’une indication concise :
Concevoir une machine qui dispose d'une seule entrée et une seule sortie.
La sortie vaut 1 si le système reçoit en entrée "1" puis "1". Autrement, la
sortie vaut "0".
• On peut représenter une machine à états finis avec les sorties sur les arcs :
E='1'/S<='0'
E='0'/S<='0' E='1'/S<='1'
Etat 0
Etat 1
Depart
E='0'/S<='0'
Entrées Combinatoire
des états
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
Remarque : En général, une machine de Moore contient plus d’états et les variables d’état sont
plus complexes. Cependant, la sortie d’une machine de Moore est plus fiable puisqu’elle est
constante pendant toute une période d’horloge, indépendamment des entrées du système.
Exemple : construire une machine à état fini pour la détection d'une séquence "0110". La
séquence doit être successive et unique. L'introduction d'une entrée fausse réinitialise la machine
à état finis et la remet à son état de départ.
Solution :
• Vecteur des entrées : 1 entrée.
• Vecteur des sorties : 1 sortie.
E='0'
Depart
E='1'
E='0'
Q0X
00 01 11 10
Q2 Q1
00 0 0 0 0
01 0 0 0 1
11 -- -- -- --
10 0 0 -- --
Q2+ = /X.Q0.Q1
Q0X
00 01 11 10
Q2 Q1
00 0 0 1 0
01 0 1 0 0
11 -- -- -- --
10 0 0 -- --
Q1+ = X.Q0./Q1 + X./Q0.Q1
Q0X
00 01 11 10
Q2 Q1
00 1 0 0 0
01 0 1 0 0
11 -- -- -- --
10 0 0 -- --
Q0+ = X./Q0.Q1 + /X./Q0./Q1./Q2
Q0X
00 01 11 10
Q2 Q1
00 0 0 0 0
01 0 0 0 0
11 -- -- -- --
10 1 1 -- --
S = Q2
a7. Schéma du circuit (Bascule D)
Q2+ = /X.Q0.Q1
Q1+ = X.Q0./Q1 + X./Q0.Q1
Q0+ = X./Q0.Q1 + /X./Q0./Q1./Q2
S = Q2
X
Q0
/Q1
Q1
X OR
/Q0 CLK /Q1
Q1
/X
/Q0
/Q1
/Q2
Q0
OR
X
/Q0 CLK /Q0
Q1
Une machine à états est l'implémentation en électronique du concept d'automate : dans un circuit
séquentiel, on mémorise une certaine forme des entrées précédentes (l'état) qui vont influencer la
sortie courante. Par exemple, pour le circuit contrôlant une lampe clignotante, on aura une
machine à états très simple : seuls deux états sont possibles (lampe allumée ou éteinte), on passe
de l'un à l'autre à chaque coup d'horloge.
On Off
Ainsi, si on veut implémenter une machine à états, il suffit de définir une série de bits définissant
l'état courant ; ainsi, à chaque coup d'horloge, on exécute un process qui va varier en fonction de
l'état courant. On préférera utiliser un signal, étant donné qu'il n'est pas utile de transmettre cette
valeur à l'extérieur ou de laisser la possibilité de l'altérer directement.
On peut donc implémenter cette lampe en VHDL. La machine à états ne contiendra que deux
états et un bit suffira pour le retenir (log2 2). La sortie O varie en même temps que le flanc
montant d'horloge et servira à actionner la lampe (ce qui est fait du signal en sortie est à gérer
manuellement à l'aide de DEL et résistances, en se basant sur les spécifications du composant
utilisé notamment en ce qui concerne le courant de sortie).
library ieee;
use ieee.std_logic_1164.all;
Etat 0
Etat 1
Reset
E='0'/S<='1'
Clk
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
Entrées Combinatoire
des états
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
• Un process combinatoire de calcul de l’état futur à partir des entrées et de l’état présent :
Entrées Combinatoire
des états
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
Etat 0 Etat 2
Etat 1 S<='1'
S<='0'
S<='0'
Reset
E='1'
E='0'
Clk
Entrées Combinatoire
des états
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
• Un process séquentiel de mise à jour de l’état présent par l’état futur sur les fronts montant
d’horloge (reset asynchrone inclus) :
type Etat is (Etat0, Etat1, Etat2);
Signal Etat_present, Etat_futur : Etat := Etat0;
Sequentiel_maj_etat : process (clk, reset)
begin
if reset = '0' then
Etat_present <= Etat0;
elsif (clk'event and clk = '1' ) then
Entrées Combinatoire
des états
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
• Un process combinatoire de calcul de l’état futur à partir des entrées et de l’état présent :
Combinatoire_etats : process (E, Etat_present)
begin
case Etat_present is
when Etat0 => if E = '1' then
Etat_futur <= Etat1;
else
Etat_futur <= Etat0;
end if;
when Etat1 => if E = ‘0' then
Etat_futur <= Etat2;
else
Etat_futur <= Etat1;
end if;
when Etat2 => if E = '1' then
Etat_futur <= Etat1;
else
Etat_futur <= Etat0;
end if;
end case;
end process Combinatoire_etats;
• Un process combinatoire de calcul des sorties à partir de l’état présent :
Etat futur
CLK
Mémorisation
état (registre)
Etat présent
Combinatoire Sorties
de la sortie
• Un process combinatoire de calcul de l’état futur à partir des entrées et de l’état présent :
Combinatoire_sorties : process (Etat_present)
begin
case Etat_present is
when Etat0 => S <= '0';
when Etat1 => S <= '0';
when Etat2 => S <= '1';
end case;
end process Combinatoire_sorties;
Exercice 1 : Compteur/Décompteur
On considère le circuit logique schématisé par la figure suivante dont les entrées CLK, CD, RAZ
sont des bits. La sortie Q du circuit est un vecteur sur deux bits.
CLK
Q
CD Comp/Dec
2
RAZ
M1
00
CD=1 CD=0
M2
CD=0 01 CD=1
CD=1 CD=0
M3
10
CD=1 CD=0
M4
11
Etat1 Etat2
reset Etat0
S=0 S=1
S=0
E=’1’
E=’0’
Etat0 E=0
S0=1
S1=0
Etat1
E=1 S0=1
S1=1
E=1
Etat2
E=0
S0=0
S1=0
Page | 57 © ISI 2013 Ridha Ghayoula
E=0
1. Identifier le vecteur d'entrée et le vecteur de sortie de cette machine à états finis.
2. Déterminer
- le nombre d’états
- le nombre de variable
3. Déterminer la Table d’états de cette machine.
4. Déterminer la Table d’états avec codage.
5. A partir de tableau de karnaugh, écrire les équations des entrées de bascules.
6. Ecrire les équations de sortie.
7. Déterminer le schéma du circuit (machine à états finis)
8. Le fonctionnement de cette machine est synchronisé par un front montant de l’horloge
CLK.
9. Ecrire un code VHDL de cette machine d’état
SdS
SfS
Le bilan des entrées et sorties est décrit ci-dessous, on y a ajouté la possibilité d’un reset avec
l’entrée rst.
S sds
rst FSM
sfs
clk
1. Réaliser la synthèse en vhdl de cette machine dans les deux cas suivantes.
a) Machine de Moore
reset Etat 0
Etat 2
Etat3
S=’0’
Sfs=1
a) Machine de Mealy
S='1'/sds<='1'
S<='0' S<='1'
Etat 0
Etat 1
Reset
S='0'/sfs<='1'
4.1. Introduction
Verilog est un langage de description de matériel, c'est-à-dire un langage utilisé pour décrire un
système numérique matériel, comme, par exemple, un flip-flop (bascule D) ou un
microprocesseur. Il peut modéliser un système par n'importe quelle vue, structurelle ou
comportementale, à tous les niveaux de description.
De plus il peut servir non seulement à simuler un système mais aussi à le synthétiser, c'est-à-dire
être transformé par des logiciels adaptés (synthétiseurs) en une série de portes logiques prêtes à
être gravées sur du silicium.
Verilog est l'un des trois grands langages de description de matériel utilisés majoritairement dans
l'industrie, avec VHDL et SystemC. Chaque langage a ses propres avantages et inconvénients,
ainsi que ses spécificités. Pour plus de détails, on pourra se référer à une comparaison objective
de VHDL et Verilog.
Verilog a été inventé par Gateway Design Automation Inc. aux alentours de 1984. C'était un
langage propriétaire, inspiré d'un autre HDL (HiLO) et du langage C.
Gateway a aussi produit le premier simulateur Verilog en 1985, ainsi que son successeur Verilog-
XL, toujours utilisé. En même temps, la société Synopsys développe le premier synthétiseur,
travaillant à partir de sources Verilog. En 1990, la société de CAO CAdence rachète Gateway.
Elle décide de rendre les spécifications de Verilog publiques, qui deviennent un standard IEEE
en 1995 (IEEE Std. 1364-1995). Dans le même temps, plusieurs sociétés développent des
simulateurs et des synthétiseurs, dont VCS le premier simulateur-compilateur (en comparaison,
Verilog-XL est un interpéteur).
L'essor de VHDL et les lacunes de Verilog 1995 ont poussé l'IEEE à créer une nouvelle version
du langage, Verilog 2001 puis Verilog 2005. Ces versions du langage sont maintenant acceptées
par la quasi-totalité des outils de l'industrie. Une extension de Verilog, appelée SystemVerilog est
actuellement introduite sur le marché. Elle cherche à modéliser les systèmes à un niveau encore
plus abstrait qu'actuellement, pouvant modéliser non seulement des systèmes matériels mais aussi
des systèmes logiciels (OS, ...) ainsi que des mélanges des deux.
4.2. Verilog
Verilog a une syntaxe proche de celle du C. Les types de données sont eux aussi proches de ceux
du C, avec des extensions spécifiques au matériel.
Les conventions lexicales de Verilog sont les mêmes que celles utilisées en C. Un code Verilog est
composé d'une suite d'éléments :
commentaires
délimiteurs
nombres
chaînes de caractères
identificateurs
mots-clefs
Verilog est sensible à la casse : tous les mots clefs doivent être en minuscules.
a) Espaces
Les espaces peuvent être au choix un espace normal (\b), une tabulation (\t) ou un retour
à la ligne (\n).
Les espaces sont ignorés, sauf quand ils séparent des éléments, ou à l'intérieur des chaînes
de caractères.
b) Commentaires
Des commentaires doivent être inclus dans le code, pour augmenter la lisibilité et la
documentation.
Il en existe deux styles, comme en C :
c) Underscore
Les underscore "_" peuvent apparaître dans les identificateurs ou dans les nombres (sauf
en premier caractère). Ils servent surtout à augmenter la lisibilité du code.
d) Identificateurs
Ils ne peuvent contenir que des lettres, des chiffres, le signe $ et le signe _ .
Ils ne peuvent pas contenir d'espace.
Les mots-clefs du langage ne peuvent pas être utilisés comme identificateurs.
0 : 0 logique
1 : 1 logique
x ou X : "inconnu", utilisé pour les signaux dont on ne connait pas la valeur
z ou Z : "haute-impédance", utilisé pour les noeus flottants ou pour exprimer
l'indifférence
Des forces peuvent éventuellement être appliquées aux valeurs logiques pour résoudre
d'éventuels conflits en cas de pilotes (drivers) multiples. Par ordre décroissant :
supply
strong
pull
large
weak
medium
small
highz
Si deux signaux différents sont appliqués à un signal, celui de plus grande force prévaut, et la
force du résultat est alors la plus grande des deux.
Si deux signaux différents de même force sont appliqués à un signal, le résultat est inconnu (x).
Les forces de signaux sont surtout utilisées pour modéliser les transistors MOS et autres
dispositifs de très bas niveau.
a)Noeuds
Les noeuds représentent les connexions entre des éléments physiques. Ils sont principalement
utilisée en description structurelle (instanciation de portes ou de modules).
Comme dans le monde réel, leur valeur leur est assignée continuement, autrement dit ils
n'ont pas de capacité de mémorisation.
Par défaut, la valeur d'un noeud est z (sauf pour les trireg, dont la valeur par défaut est x)
A moins de le préciser, un wire est sur un seul bit. On peut cependant déclarer un ensemble de
noeuds, un bus.
Lors de la déclaration d'un bus, le bit de poids fort est toujours à gauche, celui de poids
faible à droite. Dans l'exemple ci-dessus, le poids fort de bus2 est numéroté 2, celui de bus1 est
numéroté 7.
tri
même chose que wire. La convention veut que wire est utilisé dans le cas d'un pilote
simple, tri dans le cas de pilotes multiples.
wand/triand
ce sont des ET câblés. L'affectation de signaux différent à ces noeuds se résoudra par un
ET des deux signaux.
wor/trior
même chose,en OU câblés.
supply0, supply1
déclaration d'un noeud d'alimentation, de force supply.
tri0, tri1, trireg, ...
peu usités... représentent des pull-down, pull-up, ou un réseau capacitif. On se rapportera
à la norme Verilog pour plus de détails.
Remarque : on utilise dans 99% des cas des wire.
Les wire sont par défaut non signés. Si on les veut signés, on leur adjoint le mot-clef signed (voir
ci-dessous).
b)Variables
Les variables se distinguent des noeuds par le fait qu'elles ont des capacités de mémorisation.
On ne leur assigne pas de valeur en continu, mais seulement à des moments précis. Elles gardent
alors cette valeur jusqu'à la prochaine affectation. Elles sont donc utilisées pour des
descriptions comportementalesseulement.
le rôle de variables au sens traditionnel du terme (le même qu'en C, Pascal, Ada)
modéliser les signaux de communication entre processus
Par défaut, un reg est sur 1 bit. Comme pour les wire, on peut en faire des bus.
Les reg sont par défaut non signés. Si on les veut signés, on leur adjoint le mot-clef signed. Ils
sont alors représentés en complément à 2.
Exercice
integer
similaires aux reg, mais signés. Sa taille est la taille de mots de la machine hôte,
généralement 32bits.
ils sont utilisés pour compter, alors que les reg sont utilisés pour les signaux sur 1 bit, et
généralement comme variables locales.
real
définissent des nombres réels signés, représentés selon la norme IEEE Std 754-1985, un
standard sur la représentation des flottants en double précision. peuvent être utilisés en
notation
les conversion réels vers entiers se fait vers l'entier le plus proche avec la convention :
0.5 devient 1
-0.5 devient -1
Paramètres
Les paramètres sont un type particulier de variables : ils définissent des constantes. Ces
constantes permettent de construire des blocs génériques. Par exemple, au lieu de coder trois
additionneurs différents (un sur 8 bits, un sur 16, un sur 32), on n'en codera qu'un seul. Les bus
internes seront définis en fonction d'un paramètre, qui pourra être modifié au moment de la
compilation pour valoir 8, 16 ou 24.
C'est une très mauvaise habitude de coder un nombre en dur dans un code quel qu'il soit. Il vaut
bien mieux définir un paramètre (ou utiliser les #define de C), et utiliser ce paramètre en lieu et
place du nombre. Les paramètres de Verilog permettent d'avoir des #define du C un peu plus
souples (ayant une portée locale seulement).
Le type des paramètres peut être explicite, implicite ou à mi-chemin entre les deux (partiellement
implicite). Les règles suivantes permettent de clarifier les choses :
sans type et sans largeur, un paramètre a le même type que la valeur qu'on lui affecte.
sans type et avec largeur, le paramètre est vecteur de bit non signé, quelle que soit la
valeur qu'on lui affecte.
avec type et sans largeur, le paramètre est du type spécifié, sur une largeur permettant
d'accueillir la valeur qu'on lui affecte.
avec type et avec largeur, le paramètre est du type spécifié.
Les specparams sont déclarés soit dans un module, éventuellement dans un bloc specify.
Exemple :
Chaînes de caractères
Les chaînes de caractères sont définies comme des bus (vecteurs) de reg. Chaque caractère étant
codé sur 8 bits, une chaîne sera donc stockée sur un multiple de 8 regs.
Lors de l'affectation d'une chaîne,
Exemple :
La représentation générique d'un entier est [signe] [taille ' [s] base] <valeur>
taille est un nombre décimal non signé représentant le nombre de bits de l'entier.
Si taille n'est pas précisé, la taille par défaut dépend du simulateur / synthétiseur, mais
vaut au moins 32 bits.
base représente la base dans laquelle il faut interpréter valeur.
base peut être :
o d, D : décimal
o h, H : hexadécimal
o b, B : binaire
o o, O : octal
Chaque nombre porte, en plus de sa valeur, une information indiquant s'il est signé ou non :
comment il doit être interpété, en cas d'expansion notamment (extension de signe ou non). Les
règles suivantes déterminent si un nombre est signé ou non :
Si taille est plus grande que nécessaire pour représenter valeur, alors Verilog comble les bits de
gauche ainsi :
Exemple :
Exercice#1 :
Exercice #2:
Comme dans tous les langages (ou presque ?), il possible de déclarer des tableaux multi-
dimensionnels. On peut déclarer des tableaux de noeuds (wire) ou de variables (reg, integer, ...).
Les éléments du tableaux peuvent être
La déclaration de tableaux se fait en spécifiant l'étendue des dimensions entre crochets après le
nom de l'instance (une déclaration d'étendue avant le nom sert à déclarer un bus).
Exemple :
Attention : ne pas confondre un tableau de scalaires (reg xxx [7:0]) et un bus (reg [7:0] xxx). Un
bus peut être affecté en une seule instruction, tandis qu'un tableau ne peut pas : on ne peut
accédér qu'à un seul élement du tableau à la fois.
Lors d'un accès à un tableau multidimensionnel, on doit spécifier un index pour toutes les
dimensions : en d'autres termes, on ne peut pas extraire une ligne (ni une colonne) d'une matrice.
Les tableaux sont utiles pour modéliser les mémoires : une mémoire est un tableau de mots (un
mot est un vecteur de bits).
On a le droit, lors de l'accès à un tableau, de spécifier l'index par un reg (ou tout autre type
entier). Mais attention, cette construction n'est souvent pas synthétisable.
Lors d'une affectation continue, on affecte à un noeud une expression, constante ou non
(comme dans l'exemple ci-dessus). Les expressions peuvent être utilisées non seulement dans les
affectation continues, mais aussi dans les autres types d'affectation que nous verrons plus tard.
C'est l'occasion de les étudier !
Une expression combine des opérateurs et des opérandes. Une opérateur (&, |, +, ...) peut agir
sur une, deux ou trois opérandes.
Les opérandes peuvent être :
Arithmétiques : +, -, *, /, %, **
Relationnels : >, >=, <, <=
D'égalité : ==, !=, ===, !==
Logiques : !, &&, ||
Binaires : ~, &, |, ^, ^~, ~^
De réduction : &, ~&, |, ~|, ^, ^~, ~^
De décalage : <<, >>, >>>, <<<
Conditionnel : ?:
Concaténation : {}, {{}}
Evénement : or
Tous les opérateurs ne sont pas applicables à certains types. Pour les réels, les opérateurs suivants
ne peuvent pas être utilisés :
concaténation
modulo
=== et !===
binaires
Le résultat d'une opération logique ou relationelle sur des réels est un bit.
Opérateurs arithmétiques
Opérateur Commentaires
a+b somme
a-b différence
a*b produit
a/b division; la division entière tronque vers zéro.
a%b modulo; du signe de a
a ** b puissance (a puissance b)
+a prioritaire sur les autres (opérateur unaire)
-a prioritaire sur les autres (opérateur unaire)
On fera attention au signe des opérandes (voir ici pour plus de détails). On fera attention aussi au
nombre de bits de l'expression. Pour cela on se rapportera à la section sur la longueur en bit des
expressions.
Exemples :
Opérateur Commentaires
a<b a strictement plus petit que b
a>b a strictement plus grand que b
a <= b a plus petit ou égal à b
a >= b a plus grand ou égal à b
Si les opérandes ne sont pas de la même taille et qu'au moins l'un des deux est non signé, le plus
petit est complémenté à gauche avec des 0, et la comparaison s'effectue sur des nombres non
signés.
Si les deux opérandes sont signées, la relation est interprétée normalement (comme une
comparaison sur des nombres signés...)
Si l'une des deux opérandes est un réel, l'autre opérande est automatiquement convertie en réel.
Les opérandes sont comparées bit à bits, en complémentant le plus petit avec des 0 si nécessaire.
Pour == et !== (égalité et non-égalité), le résultat vaut x si l'une des deux opérande contient des
x ou z.
Opérateur Commentaires
a && b a ET b
a || b a OU b
!a NON a
Ces opérateurs travaillent sur des bits, sauf l'opérateur unaire ! qui peut accepter un type
vecteur.
Le résultat de !a vaut :
Opérateurs binaires : Les opérateurs binaires opèrent sur des bits ou des vecteurs (bus),
bit-à-bit.
Opérateur Commentaires
& ET
| OU
^ XOR
~^ ^~ XNOR
~ NOT (bit à bit)
Si les deux opérandes n'ont pas la même taille, le plus petit est complémenté à gauche avec des 0.
Opérateurs de réduction : Ce sont des opérateurs unaires (sur une seule opérande),
opérant sur des vecteurs. Ils opèrent en fait sur les bits du vecteur passé en argument, en
appliquant la fonction demandée à l'intégralité des bits du vecteur.
Le résultat est 0, 1 ou x. Les opérations de base sont le ET, le OU et le XOR (&, |, ^).
Chaque opération dispose de sa version complémentée : c'est le résultat de l'opération qui
est complémenté, pas les bits du vecteur.
Exemples :
Opérateurs de décalage
Ces opérateurs opèrent des décalages (à droite ou à gauche) sur les bits de l'opérande de gauche.
Le sens du décalage est donné par l'opérateur.
Le nombre de position décalées est donné par l'opérande de droite (qui est considérée comme
non signée).
Opérateur Commentaires
>> décalage vers la droite, les bits entrants sont des 0
<< décalage vers la gauche, les bits entrants sont des 0
<<< décalage vers la gauche, les bits entrants sont des 0
>>> décalage vers la droite. Le bit entrant est
L'opérateur conditionnel est très utilisé pour modéliser les sorties de portes 3-états :
Opérateur de concaténation
Cet opérateur permet de créer des bus à partir de bits ou de bus plus petits.
Exemple :
Avant d'évaluer une expression, il est primordial de savoir sur combien de bits ça doit se faire.
Par exemple, lors de l'addition de deux bus de 8 bits, il est important de savoir si la somme est
effectuée sur 8 bits ou sur 9 (permettant de détecter une retenue sortante).
La taille intrinsèque d'une expression est déterminée par la table suivante, das laquelle :
On appelle LHS le membre de gauche d'une affectation, RHS le membre de droite. On distingue
trois cas :
taille(LHS) = taille(RHS) : tout va bien, le membre de droite est évalué sur sa taille
intrinsèque
taille(LHS) < taille(RHS) : le membre de droite est évalué sur sa taille intrinsèque, puis le
résultat est tronqué. Cela peut faire perdre un éventuel bit de signe !!!
taille(LHS) > taille(RHS) : le membre de droite est évalué sur la taille du membre de
gauche.
Exercice :
Dans l'exemple ci-dessus, on voudrait que la somme soit calculée sur 16 bits, avec éventuellement
une retenu sortante, puis décalée de 1 bit vers la droite en faisant entrer l'éventuelle retenue.
Ce code ne fonctionne pas correctement : Expliquez pourquoi !!!
Une solution à ce problème serait de forcer le résultat intermédiaire à avoir une taille d'au moins
17 bits, ce qui peut se faire en ajoutant 0 (un entier, qui sera donc au moins sur 32 bits) :
Réponse :
Qu'affichera le code suivant ? Essayez de répondre de tête avant de simuler pour vérifier !
les entiers et les réels, comme on l'a déjà vu, sont signés
si les deux opérandes sont signées alors le résultat est signée, sinon il est non signé
sauf dans le cas d'une comparaison, où le résultat est non signé de toutes façons
les champs de bits sont non signés, même s'ils prennent toute la largeur du vecteur !!!
Récapitulation
On rassemble le tout ! Les expressions sont calculées ainsi :
1. on calcule la taille du résultat (la taille de l'expression) comme on l'a vu plus haut
2. on calcul le type du résultat (s'il est signé ou non)
3. on propage ce type et cette taille à toutes les opérandes là où ça a un sens
4. on effectue les opérations...
Exercice #2:
Verilog, comme C, accepte des directives de compilation (les équivalents des #define et
#include...). Ces directives de compilation ont la forme suivante : `define et `include (le premier
caractère est celui obtenu sur un clavier de PC par AltGr et 7).
Inclusion de fichiers
Attention : si le nom du fichier spécifie un chemin relatif, alors c'est par rapport au répertoire
d'où la simulation est lancée ! C'était le cas dans les anciens compilateurs C, mais ce
comportement a été modifié depuis. Il est resté en Verilog, les gens s'occupant de la norme ayant
eu peur de casser la sémantique des design existants.
Définitions
Il est possible, comme en C avec les #define, de créer des macros textes à l'aide des directives
`define et `undef. Mais contrairement au C, ces définitions ont un scope global : dès qu'elles
sont rencontrées par le simulateur / synthétiseur, elles sont valables pour tous les fichiers lus
après. Pour éviter des warning de re-définition de macros, il suffit d'utiliser des gardes, comme en
C:
Exemple:
Attention de ne pas abuser de ce mécanisme ! Certains objets (fonctions, tâches) ont besoin
d'être ré-instanciés, par exemple les fonctions et tâches qui ont un scope local !..
Compilation conditionnelles
C'est comme en C : `ifdef, `ifndef, `else, `elsif, `endif
Ces directives sont souvent utilisées pour séparer code synthétisable et code non synthétisable :
un attribut assez répandu étant synthesis, on peut écrire le code suivant :
Par défaut, un objet non déclaré est de type wire (net sur 1 bit). Il est possible de changer ce
comportement en utilisant la directive `default_nettype <type>.
Ménage...
La directive `resetall permet de remettre à zéro toutes les directives de compilation précédentes
(définitions, types par défaut etc...). On l'utilise typiquement en début de chaque fichier, suivi de
toutes les définitions qu'on souhaite appliquer à ce fichier.
La représentation des nombres entiers est parfois pénible si on oublie ce qu'on manipule.
Il vaut mieux parfois travailler sur des reg non signés, et faire attention lors des extensions
de signe.
Exemples :
Exemple #1 AND3
Commençons par le plus simple des modules ou presque : une porte combinatoire AND à trois
entrées. En Verilog, comme en SystemC, les blocs sont appelés modules.
Voici une description possible d'une porte AND à 3 entrées.
Passez la souris sur les différents éléments du code pour avoir des explications sur la signification
de chaque instruction.
Solution#1
les expressions
concaténation de signaux pour créer un bus
Rappel : un additionneur complet 1 bit a trois entrées (a, b, et cin la retenue entrante), et deux
sorties (le bit de somme s et le bit de retenue sortante cout).
Solution#2
Exemple #3
Verilog, comme tous les HDL, permet de décrire les système sous forme structurelle. C'est-à-dire,
au lieu de décrire un gros système dans un seul gros fichiers, de le séparer en sous-systèmes
(sous-modules), eux-mêmes subdivisés en sous-modules, jusqu'à obtenir des modules facilement
compréhensibles.
Nous allons ici décrire un additionneur 8 bits en assemblant des additionneurs 1 bit. On aurait
aussi pu décrire la fonctionnalité de l'additionneur 8 bits (par opposition à sa structure), cela sera vu
à la fin de cet exemple-ci.
On suppose ici que le code de l'additionneur 1 bit vu précédement est disponible, soit dans un
fichier à part, soit dans le fichier de l'additionneur 8 bits
Solution#3
Plutôt que de décrire l'additionneur 8 bits sous forme d'assemblage d'additionneurs 1 bits, on
aurait pu directement décrire son comportement (sa fonctionalité). En vous inspirant du code de
l'additionneur 1 bit, écrivez une description concise de l'additionneur 8 bits.
Solution#4
Exemple #5 Bascule D
Jusqu'à présent, les modules étudiés étaient purement combinatoires. Nous allons maintenant
voir comment décrire un module séquentiel.
Solution#5
Voici une description possible d'un compteur synchrone sur 8 bits, avec reset asynchrone actif à
l'état bas.
Solution#6
concurrence et séquentialité
affectations différées
On cherche à réaliser un registre à décalage sur 8 bits, possèdant une sortie supplémentaire
(match) active à 1 si le contenu du registre à décalage vaut une valeur précise (val).
Solution#7
Solution#8
Exemple #9 Multiplexeur
Solution#7
- 16 étapes
- Largeur des données 8 bits
- Signaux d'état:
Plein: élevé lorsque le FIFO est complètement plus bas.
Vide: haut quand FIFO est vide, sinon trop bas.
Overflow: élevé lorsque FIFO est plein et toujours en train d'écrire des données dans
FIFO, sinon bas.
Underflow: haut lorsque FIFO est vide et toujours lire les données de FIFO, sinon bas.
Seuil: élevé lorsque le nombre de données dans FIFO est inférieur à un seuil spécifique,
sinon inférieur.
wenable 0 0
1 1
wdata[DATA_WIDTH-1:0]
wdata[DATA_WIDTH-1:0]
0 FIFO
1 stages
ASIZE-1
ASIZE-1
ASIZE-2
ASIZE-2
a) FIFO_MEM
data_out[7:0]
wr
rd fifo_full
clk
fifo_empty
rst_n FIFO_MEM
fifo_threshold
data_in[7:0]
fifo_overflow
fifo_underflow
b) Memory_array
data_in[7:0]
c) read_pointer
d) status_signal
wr
rd
clk fifo_full
rst_n fifo_empty
status_signal
wptr[4:0] fifo_threshold
rptr[4:0] fifo_overflow
fifo_we fifo_underflow
fifo_rd
e) write_pointer
6.1. Introduction
La modulation de largeur d’impulsion permet de faire varier la vitesse d’un moteur. On souhaite
Réaliser grâce à un composant programmable du type FPGA une modulation de largeur
d’impulsion MLI ou PWM (pulse width modulation). La forme de l’onde sera très simple et non
optimisée pour réduire le taux d’harmonique.
Dans ce chapitre on va implementer un générateur d'implustion PWM sur FPGA en utilisant le
verilog.
Comment faire varier la vitesse d'un moteur ?
Rappels:
Un moteur à courant continu alimenté par une tension U peut être modélisé par une résistance r
en série avec une inductance L, E étant la force électromotrice du moteur:
L r
I
E
U
di
U E ri L 7.1
dt
De plus, on sait par les lois de l'électromagnétisme que :
E kw 7.2
La force électromotrice est proportionnelle à la vitesse
Cp k i 7.3
Le couple est proportionnel à l'intensité
M
U
Pour modifier la vitesse de rotation d'un moteur, il faut faire varier la fem E en agissant
sur:
- la tension U Commande en tension
- le courant I => Commande du couple
Periode
T
U
Rapport Cyclique
T0
T
u (t )dt U max .t 00 U max . 0
1 1 T
U moy
T
T 0 T T
Un signal PWM est un signal dont la période est fixe, mais le rapport cyclique varie. En d’autres
termes, t1 et t2 varient tout en conservant t1+t2=T=constante.
1
T
0.5
t1 t2
VCC
VMOY t1
T
6.2. 2. Fréquence du PMW
La commande d'actionneurs de puissance par PWM est très liée à la notion de fréquence. Pour
que l'impression d'une va leur moyenne constante d'allumage apparaisse, il faut que l'alternance
d'allumage/extinction soit suffisamment rapide pour qu'elle ne se remarque pas.
PWM_out
Decrease_duty
increase_duty
PWM
7.1. Introduction
L'architecture MIPS (de l'anglais : microprocessor without interlocked pipeline stages) est une
architecture de processeur de type Reduced instruction set computer (RISC) développée par la
société MIPS Technologies (alors appelée MIPS Computer Systems), basée à Mountain View en
Californie. Les processeurs fabriqués selon cette architecture ont surtout été utilisés dans les
systèmes SGI. On les retrouve aussi dans plusieurs systèmes embarqués, comme les ordinateurs
de poche, les routeurs Cisco et les consoles de jeux vidéo (Nintendo 64 et Sony PlayStation,
PlayStation 2 et PSP). Vers la fin des années 1990, on estimait que les processeurs dérivés de
l'architecture MIPS occupaient le tiers des processeurs RISC produits.
end Behavioral;
b) ALU
Code VHDL pour ALU du processeur MIPS:
d) Register File
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE IEEE.numeric_std.all;
-- VHDL code for the register file of the MIPS Processor
entity register_file_VHDL is
port (
clk,rst: in std_logic;
reg_write_en: in std_logic;
reg_write_dest: in std_logic_vector(2 downto 0);
reg_write_data: in std_logic_vector(15 downto 0);
reg_read_addr_1: in std_logic_vector(2 downto 0);
reg_read_data_1: out std_logic_vector(15 downto 0);
reg_read_addr_2: in std_logic_vector(2 downto 0);
reg_read_data_2: out std_logic_vector(15 downto 0)
);
end register_file_VHDL;
end Behavioral;
e) Control Unit
Code VHDL pour Control Unit du processeur MIPS:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- VHDL code for Control Unit of the MIPS Processor
entity control_unit_VHDL is
port (
opcode: in std_logic_vector(2 downto 0);
reset: in std_logic;
reg_dst,mem_to_reg,alu_op: out std_logic_vector(1 downto 0);
jump,branch,mem_read,mem_write,alu_src,reg_write,sign_or_zero: out std_logic
);
end control_unit_VHDL;
begin
process(reset,opcode)
begin
if(reset = '1') then
reg_dst <= "00";
mem_to_reg <= "00";
alu_op <= "00";
jump <= '0';
branch <= '0';
mem_read <= '0';
mem_write <= '0';
end Behavioral;
f) Instruction Memory
end Behavioral;
g) Porcesseur MIPS
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_signed.all;
-- fpga4student.com: FPGA projects, Verilog projects, VHDL projects
-- VHDL project: VHDL code for single-cycle MIPS Processor
entity MIPS_VHDL is
port (
clk,reset: in std_logic;
pc_out, alu_result: out std_logic_vector(15 downto 0)
);
end MIPS_VHDL;
end Behavioral;
Afin de prendre en main le langage et les différents outils logiciels que nous devrons utiliser. Ils
sont tous intégrés dans l’environnement ISE 14.6 de Xilinx qui propose à la fois éditeur de texte,
synthétiseur logique, simulateur, implémentation et programmation des composants logiques
(FPGA) que nous emploierons. Toutefois, il sera possible au cours des séances d’utiliser le
simulateur MODELSIM SE comme simulateur VHDL (Simulateur utilisé dans l’industrie) ou
bien le ISim Simulator.
Ces séances de travaux pratiques sont au nombre de sept. Elles se dérouleront en deux parties :
La conception du code VHDL doit rester générique et configurable par l’utilisateur sur le PC
sans reprogrammer le FPGA. Ainsi nous verrons comment le VHDL permet la substitution des
équations logiques pour mettre en œuvre des circuits numériques combinatoires et séquentiels et
l'écriture de testbenchs.
Pour vérifier matériellement les différentes entités développées on va utiliser une carte FPGA
XILINX Kintex-7 FPGA KC705 Evaluation Kit.
La carte FPGA XILINX Kintex-7 offre un environnement de conception très adapté pour le
prototypage d’applications variées dont celles des systèmes numériques à usage général et des
systèmes embarqués. Cette carte est de plus idéale pour les applications de traitement vidéo et de
traitement de signal en général.
Caractéristiques principales:
Configuration
A bord circuits de configuration JTAG pour activer la configuration via USB
JTAG header prévu pour une utilisation avec des câbles de téléchargement de Xilinx
comme la plate-forme câble USB II 128 Mo (1024Mo) Linear BPI en Flash pour PCIe ®
Configuration
16 Mo (128 Mo) Quad Flash SPI
Memory
1GB DDR3 SODIMM 800MHz / 1600Mbps
128MB (1024Mb) Linear BPI Flash for PCIe® Configuration
16MB (128Mb) Quad SPI Flash
8Kb IIC EEPROM
SD Card Slot
Communication & Réseaux
Gigabit Ethernet GMII, RGMII et SGMII
SFP / SFP + cage
Port GTX (TX, RX) avec quatre connecteurs SMA
Pour UART USB Bridge
PCI x8 connecteur de bord express
(Display) Afficher
Sortie vidéo HDMI
Dispositif Phy / codec externe conduite d'un connecteur HDMI
Pour une description approfondie de la carte XILINX Kintex-7 FPGA, consultez le manuel
d’utilisation ainsi que la fiche technique disponible chez DIGILENT.
Schéma
Langage HDL
Simulation fonctionnelle
ISim
Synthèse
XST
Implémentation
- mapping
- placement
- Routage Simulation avec Timings
- Génération des fichiers
de configuration ISim
Le logiciel Xilinx ISE est un outil de conception de circuit pour FPGA de Xilinx. Ce logiciel
permet essentiellement d’effectuer les différentes étapes propres à la synthèse de circuits
numériques sur FPGA. Il est alors possible d’en faire l’implémentation sur les différentes
familles de puces fournies par Xilinx.
Le Navigateur de projet ISE sera utilisé comme outil de conception par excellence lors de ce
didacticiel ainsi que lors des travaux pratiques. Cet outil de Xilinx permet de créer des projets
comportant plusieurs types de fichiers (HDL, schématique, UCF, EDIF, etc.), de compiler,
d’effectuer des design rule check (DRC), de créer des contraintes d’implémentation dont des
contrainte de timings sur les horloges, de déterminer l’emplacement des broches, de créer des
bancs d’essai de simulation (testbench) et de gérer efficacement les projets d’envergure.
TD
Prenons l’exemple montré par3la D
figure suivante : STRUCTURELLE
ESCRIPTION
A Porte_and S
B FPGA Kintex-7
FPGA KC705
Nous considérons un circuit simple formé par une porte ET. Afin de connecter les deux entrées
« A » et « B » au deux interrupteurs SW11(0)et SW11(1) ainsi que la sortie « S » au GPIO LEDS
(0).
Pour débuter cette partie, créez un nouveau projet ISE ayant pour cible le FPGA XILINX
Kintex-7 FPGA KC705 Evaluation Kit.
2. Dans le Navigateur de projet ISE, cliquez sur File > New Project, ou cliquez sur le bouton
New Project dans la fenêtre de gauche.
3. Dans la fenêtre New Project Wizard , tapez Lab0_porte_and comme nom de projet. et
cliquez sur Next.
Notez que Lab0_porte_and est ajouté au chemin initial contenu dans le champ Location.
6. Vous avez créé une page de schéma vide pour porte_and. L’étape suivante consiste à ajouter
les étiquettes d’entrées/sorties comme illustré à la Figure suivante. Les étiquettes
d’entrées/sorties définissent les ports. Ces ports correspondront aux broches du symbole
représentant le module.
Tapez A et B dans le champ Inputs et tapez S dans le champ Outputs et Cliquez sur Ok.
Notez que dans le champ Direction, choisissez In pour les entrées et Out pour les sorties et ne
cochez pas les champs Bus.
Figure 9. La boîte de dialogue pour entrer les ports d’entrées/sorties du module VHDL à
créer.
Figure 10.
8. Cliquez enfin sur Finish dans la fenêtre Project Summary.
Le fichier VHDL vide décrivant le module porte_and s’ouvre dans l’espace de travail
comme montré à la Figure 11. Ce fichier contient l’entité du module mais présente une
architecture vide à compléter.
Figure 11. Module porte_and s’ouvre dans l’espace de travail (Architecture vide)
Figure 12. Module porte_and s’ouvre dans l’espace de travail (Architecture complète)
- Vérifiez les résultats dans la Console et corrigez les erreurs de syntaxe s’il y a lieu.
- Vous pouvez voir le rapport de synthèse (Figure 12)
1. Ouvrez tout d’abord le projet Porte_and dans le Navigateur ISE, si ce n’est pas déjà fait.
Vérifiez ensuite que ISE pointe correctement sur l’outil de simulation Isim. Suivez ces étapes :
- Sélectionnez Project > Design Properties.
- Vérifiez que Isim(VHDL/Verilog) est bien le Simulator
- Cliquez sur Ok pour fermer la boîte de dialogue.
Dans le Navigateur de projet ISE, cliquez sur File > New Source, ou cliquez sur le bouton New
Project dans la fenêtre de gauche.
Vous devez tout d’abord configurer les propriétés des outils d’implémentation. Suivez ces étapes
:
1. Sélectionnez l’onglet Design dans l’espace Hierarchy situé dans la partie supérieure gauche du
Navigateur de Projet.
2. Assurez-vous que l’item Implementation est sélectionné dans la liste View au dessus de
l’espace Hierarchy.
3. Sélectionnez l’item top level porte_and dans l’arborescence de projet.
4. Dans l’espace Processes, sous l’espace Hierarchy, cliquez avec le bouton de droite de la souris
sur l’item Implement Design. Selectionnez Process Properties.
5. La boîte de dialogue Process Properties apparaît. Sélectionnez l’item Place & Route
Properties de la liste Category de Gauche.
6. Assurez-vous que l’item Advanced est sélectionné dans la liste Property display level, dans le
bas de la boîte de dialogue.
7. Changez le Place & Route Effort Level (Overall) pour High dans la colonne Value juste à
côté.
Vous devriez avoir un résultat conforme à la Figure 19.
Remarquez que l’étape de synthèse du projet s’effectue automatiquement dans l’espace Processes.
Figure 21. Configuration à adopter pour la boîte de dialogue Process Properties pour les
options de placement et routage.
B- Création du fichier de programmation
Pour réaliser les options Synthesize –XST, Implement Design et Generate Programming
File, il faut faire un clique-droit sur chacun, puis Run. Notez qu’il est également possible d’utiliser
l’option Implement Top Module pour réaliser les deux premières tâches.
Synthesize –XST : Permet de faire la synthèse du circuit en bloc configurable se retrouvant sur le
FPGA. Implement Design : Permet de faire les mapping et routage nécessaires pour placer le
tout sur le FPGA. Generate Programming File : Genere le fichier (.bit) utilisé pour programmer
le FPGA.
ISE lance le programme intégré BitGen pour générer le fichier BIT qui servira à programmer le
FPGA.
Après chacune des étapes, un message de succès devrait s’afficher dans la console. Dans le cas
contraire, il faut corriger les erreurs ou inspecter les avertissements (warnings) pour vous assurer
qu’ils ne proviennent pas d’erreurs dans votre code. Idéalement, on devrait voir s’afficher les trois
crochets verts illustrés à la figure précédente.
Lors de ces différentes étapes, plusieurs données deviendront disponibles dans le Design
Summary (voir figure précédente). Vous aurez donc aisément accès, entre autres, aux ressources
utilisées et aux résultats temporels (chemin critique, etc).
Dans Xilinx ISE, cliquez deux fois sur Configure Target Device.
Lorsque l’outil iMPACT sera ouvert, double clik sur Boundary Scan et dans l’espace en blanc, cliquez sur
le bouton de droite et choisissez Initialize Chain.
Cliquez sur Yes si la fenêtre « Auto Assign Configuration Files Query Dialog » s’affiche. Choisissez le
fichier porte_and.bit que vous trouverez dans le dossier projet et cliquez sur Open. Si le logiciel vous
demande d’attacher un SPI ou un BPI PROM, répondez par No. Cette option sert à charger la mémoire
PROM de la planchette. Cliquez sur le symbole représentant le FPGA, puis sur le bouton de droite de la
souris. Choisissez Program … Cliquez sur OK dans la fenêtre Device Programming Properties (si elle
s’affiche), sans rien changer.
En codage BCH : (Binary Coded Hexadecimal, soit hexadécimal codé binaire en français), on
TD
prend chaque chiffre qui compose
Exemple : F 0 5 = 1111 0000 0101
3 D
une S
valeur hexadécimal,
ESCRIPTION et on le code directement sur 4 bits.
TRUCTURELLE
Le but de ce Lab est d’afficher la valeur d’une entrée de 4 bit (BCH) en une valeur hexadécimal
(0, 1, ..., 9, A, B, …, F)
Exemple :
si BCH = 1110 = E en hexadécimal (=14 en décimal) alors l’afficheur 7 segment affichera la
lettre E.
si BCH = 0010 = 2 en hexadécimal alors le chiffre 2 sera afficher.
a
a
f b
BCH SEG
g
/ DecHex /
4 bits 7 bits
e c
d
BCH abcde fg
"0010" "1 1 0 1 1 0 1"
Architecture :
Les entrées:
Eight user LEDs (callout 22)
GPIO_LED_[7-0]: DS27, DS26, DS25, DS3, DS10, DS1, DS4
CLK
Q
SENS
RAZ
CMP_DEC /
4 bits
Figure 1. Compteur/Décompteur.
Inputs Outputs
RAZ SENS CLK Q(3) Q(2) Q(1) Q(0)
1 x x 0 0 0 0
0 1 Incrémentation
0 0 Décrémentation
Ai Bi
Cout Cin
FA
Si
Figure 1. Additionneur FA
e) Ecrire les équations des sorties Si et Cout (en utilisant des portes AND, OR et XOR).
f) Ecrire un programme en VHDL avec une description de type flot des données pour cet
additionneur (FA).
g) A partir de ce schéma, écrire en VHDL un modèle uniquement structurel de
l'additionneur 4 bits en utilisant l’additionneur 1 bit (FA) déjà décrit.
A3 B3 A2 B2 A1 B1 A0 B0
Cout i3 i2 i1 Cin
FA FA FA FA
S3 S2 S1 S0
Les entrées
4-position user DIP Switch (callout 24)
GPIO_DIP_SW[3:0]: SW11
4-Poles DIP Switch
Y29 GPIO_DIP_SW0 SW11.4
W29 GPIO_DIP_SW1 SW11.3
AA28 GPIO_DIP_SW2 SW11.2
Y28 GPIO_DIP_SW3 SW11.1
Tableau 1. GPIO Connections to FPGA U1 (4-Poles DIP Switch)
FPGA Pin (U1) Schematic net GPIO Pin
Name
Indicator LEDs (Actice High)
AB8 GPIO_LED_0 DS4.2
AA8 GPIO_LED_1 DS1.2
AC9 GPIO_LED_2 DS10.2
AB9 GPIO_LED_3 DS2.2
AE26 GPIO_LED_4 DS3.2
G19 GPIO_LED_5 DS25.2
E18 GPIO_LED_6 DS26.2
F16 GPIO_LED_7 DS27.2
Tableau 2. GPIO Connections to FPGA U1(Indicator LEDs)
Partie II : Modélisation d’un Soustracteur
Comme pour l'additionneur, un soustracteur peut être réalisé en cascadant les cellules de base.
Ecrire un programme en VHDL avec une description structurelle pour ce soustracteur (en
utilisant les fils internes i1, i2, i3, b0, b1, b2 et b3).
B3 B2 B1 B0
A3 A2 A1 A0
b3 b2 b1 b0
Cout i3 i2 i1 ‘1’
FA FA FA FA
S3 S2 S1 S0
E2 E 1 E0
Transcodeur
S2 S 1 S0
S1S0 Fonction
00 inchangé
01 chargement
10 Déc gauche
11 Déc droit
4 bits
2 bits
IL E IR
S1..0
REGISTRE
H
Q
4 bits
CS_A
8 bits
CS_B
Dec_Adress
Adresse CS_C
Donnez un nom à votre projet, ici Lab_SE, et choisissez comme emplacement votre
répertoire de projet. Cliquez sur Next.
Cliquez sur Project Settings à gauche pour ouvrir la fenêtre des paramètres du projet.
Changez le langage de programmation de Verilog à VHDL en changeant l’option Target
Language de l’onglet General. L’onglet Simulation est l’endroit où le logiciel de
simulation peut être modifié ; toutefois, le logiciel utilisé au cours du laboratoire est celui
sélectionné par défaut, Vivado Simulator.
Le nom des broches doit correspondre au nom des ports de l’entité du fichier du niveau
hiérarchique supérieur (top level). Ces broches sont définies dans un fichier de contraintes de
type XDC
Les commentaires sont indiqués par #. Remarquez que le nom de la broche, après get_ports,
correspond au nom du signal dans le fichier du niveau hiérarchique supérieur (top level),
Pour ajouter des sources VHDL déjà écrites à l’aide d’un autre éditeur de fichiers, cliquez
sur Add Sources, puis sélectionnez Add or create design sources et appuyez sur Next.
Cliquez sur Add files et sélectionnez les fichiers suivants : Partie I : Mémoire ROM
asynchrone
Mémoire RAM Les exemples qui suivent présentent la description VHDL des mémoires RAM
les plus couramment utiles : la RAM synchrone, la RAM à double port synchrone (un port en
lecture et un port en écriture) et la RAM à double port complet synchrone à deux horloges.
Les ressources matérielles de la plupart des FPGA, dont le Artix-7, permettent d’implémenter
des mémoires RAM à l’aide de RAM distribuée ou de RAM en blocs (block RAM).
Habituellement, il est préférable d’utiliser les blocs RAM pour les grandes capacités de mémoire
et d’utiliser la mémoire distribuée pour les plus petites capacités afin d’avoir localement les
données.
entity RAM_1p is
Port ( clk_i : in std_logic;
we_i : in std_logic;
add_i : in std_logic_vector(4 downto 0);
data_write_i : out std_logic_vector(15 downto 0);
data_read_o : out std_logic_vector(15 downto 0) );
end RAM_1p;
P_sync: process(clk_i)
begin
if clk_i’event and clk_i=’1’ then
if we_i =’1’ then
RAM_1p(to_integer(unsigned(add_i)))<= data_write_i;
end if;
data_read_o <= RAM_1p (to_integer(unsigned(add_i)));
end if;
end process;
end arch_RAM_1p;
Le code suivant implémente une RAM synchrone avec un port en écriture (p1) et un port
en lecture (p2).
Description du fichier RAM_2p.vhd
entity RAM_2p is
Port (
clk_i : in std_logic;
we_p1_i : in std_logic;
add_p1_i : in std_logic_vector(4 downto 0);
add_p2_i : in std_logic_vector(4 downto 0);
data_write_p1_i : in std_logic_vector(15 downto 0);
data_read_p2_o : out std_logic_vector(15 downto 0) );
end RAM_2p;
Le code suivant implémente une RAM synchrone à double port complet synchrone à
deux horloges.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity RAM_2p_full is
P_sync_p2: process(clk_p2_i)
begin
if clk_p2_i’event and clk_p2_i=’1’ then
if we_p2_i =’1’ then
RAM_2p_full (to_integer(unsigned(add_p2_i))) := data_write_p2_i;
end if;
data_read_p2_o <= RAM_2p_full (to_integer(unsigned(add_p2_i)));
end if;
end process;
end arch_RAM_2p_full;
C'une carte a base de circuit FPGA de la série 7 du fabricant Xilinx qui utilise une
technologie de lithographie de 28nm et qui possède beaucoup de ressources par rapport
aux autres composants. Les FPGA Artix-7 sont optimisés pour les applications à faible
puissance et à coût réduit. En comparaison avec les autres familles de FPGA de Xilinx,
cette famille possède des performances supérieures à la famille d’entrée de gamme
Spartan-7 ; toutefois, les familles Kintex-7 (haut de gamme – optimisée pour le ratio prix-
performance) et Virtex-7 (très haut de gamme – optimisée pour les performances et les
capacités) sont plus performantes.
Arty est une plate-forme de développement prête à l'emploi conçue autour Artix-7 ™ (FPGA) de
Xilinx. Il a été conçu spécifiquement pour être utilisé comme système de traitement souple
MicroBlaze. Lorsqu'il est utilisé dans ce contexte, Arty devient une plate-forme de traitement
incroyablement flexible, capable de s'adapter à tous les besoins de votre projet. Contrairement à
d'autres ordinateurs à carte unique, Arty n'est pas lié à un seul ensemble de périphériques de
traitement; un instant, il s'agit d'une centrale de communication remplie de UART, SPI, IIC et
Ethernet MAC, et ensuite d'un chronométreur méticuleux avec une douzaine de minuteries 32
bits. De plus, avec les en-têtes d'expansion universellement répandus (en-têtes Arduino ™ R3 et
nos en-têtes Pmod ™), Arty deviendra l'outil le plus adaptable de votre boîte à outils de projet.
L'échelle de temps 1ns / 1ps de la partie échelle de temps fournit une durée de base suivie d'une
résolution temporelle minimale. D'une manière générale, ceci n'est utilisé que pendant la
simulation et si des retards sont spécifiquement implémentés dans le HDL, ce que nous ne
faisons ni l'un ni l'autre, mais qui fait néanmoins partie intégrante des modules Verilog.
La partie module
La partie assigner affecte led = sw; définit ce que fait notre «boîte noire». Plusieurs instructions
d'affectation peuvent être utilisées en fonction des besoins, ainsi que d'autres moyens de définir
ce que fait notre «boîte noire» (ce que nous verrons dans un didacticiel ultérieur).
Le module endmodule est le mot-clé qui indique la fin de notre définition du contenu de notre
module (notre boîte noire). D'autres modules pourraient alors être créés avec leur propre
ensemble d'entrées et de sorties, assigner des instructions et, bien sûr, les modules de fin.
9) Assurez-vous que le bouton Copier les fichiers de contraintes dans le projet est coché. Cela
vous garantit de modifier ultérieurement une copie du fichier xdc principal, plutôt que le fichier
d'origine. Puis cliquez sur Suivant.
10) Ici, vous voudrez sélectionner le FPGA que vous utilisez pour vous assurer que Vivado
conçoit et programme correctement le matériel. Vous pouvez effectuer une recherche par
numéro de pièce FPGA à partir de l'onglet Pièces ou sélectionner votre tableau à partir de
l'onglet Tableaux si vous disposez d'un fichier de carte. Digilent dispose de fichiers de carte pour
chacune de leurs cartes sur GitHub; Vous pouvez suivre un tutoriel sur la façon de les installer
sur votre ordinateur ici. Une fois que vous avez choisi la pièce (ou la carte) FPGA appropriée,
cliquez sur Suivant.
11) Confirmez que votre projet a ce que vous voulez avoir (au moins au début) et cliquez sur
«Terminer».
12) Après un bref chargement, nous vous présentons un assistant de module supérieur (puisque
nous avons dit que nous créions notre propre fichier source appelé «top»). Pour ce projet, nous
voulons avoir une entrée appelée «sw» et une sortie appelée «led». Les deux étant des entrées et
des sorties simples, laissez la case de bus non cochée pour les deux. Cliquez sur OK lorsque vous
avez terminé.
16) Nous allons maintenant éditer notre fichier de contraintes. Nous pouvons trouver notre
copie du XDC dans la fenêtre des sources dans le dossier Constraints → constrs_1. Double-
cliquez dessus pour l'ouvrir dans la fenêtre de l'espace de travail.
17) Notre XDC sera visible dans la fenêtre de l’espace de travail (comme mentionné dans l’étape
ci-dessus). Comme il s’agit d’un fichier maître XDC (du moins pour moi), il ya beaucoup de
lignes de texte, nous ne voulons donc que décommenter les broches que nous utilisons et
changer le nom de la pin pour correspondre aux noms de nos entrées et sorties. module.
18) Les deux lignes que je décomment dans ce projet seront la ligne correspondant au premier
commutateur (étiqueté SW0 sur l’écran de soie de l’Arty) et la ligne correspondant à la première
LED monochrome (étiquetée LD4 sur l’écran de soie de l’Arty). l'Arty). J'ai renommé le
commutateur (broche A8 sur le FPGA) en sw et renommé la LED (broche H5 sur le FPGA) en
led. Appuyez sur Cntr + S pour enregistrer vos modifications.
19) Cliquez sur le bouton Run Synthesis (Exécuter la synthèse) situé sur le côté gauche de
l'interface graphique Vivado.
20) Un assistant apparaîtra qui vous permettra de choisir vos options de synthèse. Vous voudrez
lancer votre projet dans le répertoire local et l'exécuter sur l'hôte local (par opposition à la
génération de scripts uniquement).
En passant, toute la combinaison de la synthèse, de l'implémentation et de la génération du
bitstream pour programmer le FPGA peut prendre un peu de temps (plus de 10 minutes dans
certains cas) puisque Vivado traite une tonne de choses cachées à l'utilisateur. et fonctionne avec
tout le FPGA et pas seulement ce que nous utilisons, donc vous voudrez probablement
maximiser le nombre de travaux (les cœurs d'ordinateurs Vivado sont autorisés à utiliser) à moins
que vous envisagiez de faire beaucoup d'autres choses en même temps.
Lorsque vous êtes satisfait de vos sélections, cliquez sur OK.
21) Après avoir cliqué sur OK, vous devez attendre que la synthèse soit terminée, ce qui peut
prendre une minute ou deux, en fonction de la vitesse d'exécution de votre ordinateur.
21) Cliquez sur Exécuter l'implémentation sur le prochain assistant qui apparaît, puis cliquez sur
OK. Vous pouvez encore choisir le nombre de tâches (les cœurs que votre ordinateur utilise) si
vous n'avez pas cliqué sur la case «Ne pas afficher cette boîte de dialogue» la dernière fois.
22) Après avoir cliqué sur ok, vous devez attendre que l'implémentation se termine, ce qui peut
prendre une minute ou deux selon la vitesse d'exécution de votre ordinateur.
29) Le fichier bitstream lui-même est un peu peu intuitif à trouver. Vous pouvez le trouver en
ouvrant le dossier dans lequel vous avez demandé à Vivado de sauvegarder votre projet, accédez
à <projectName> .runs, puis impliquez_1, puis choisissez le fichier .bit que vous voyez. J'ai
nommé mon module Verilog top.v, donc le fichier bit est top.bit. Puis cliquez sur OK.
30) Enfin, nous pouvons cliquer sur Program; le processus de programmation prend moins de 10
secondes pour tout ordinateur, donc il n’est pas trop difficile d’attendre
Partie 1:
Arty est une plate-forme de développement prête à l'emploi conçue autour Artix-7 ™ (FPGA) de
Terminologie
Avant de nous lancer dans la pratique de la création de notre premier projet, je devrais expliquer
quelques termes du titre:
Verilog est un langage de description de matériel (HDL) qui vous permet d'exprimer votre
conception à un niveau supérieur au lieu de décrire directement des portes logiques. Ceci est à
peu près analogue à la manière dont C vous permet d'exprimer votre conception de logiciel à un
niveau supérieur à celui du langage d'assemblage. Les autres HDL incluent VHDL et Chisel.
Vivado est la suite de développement FPGA de Xilinx. Il comprend tout ce dont vous avez
besoin pour écrire Verilog et programmer un FPGA Xilinx. Il n'y a pas à contourner le fait que
c'est un monstre: nécessitant environ 20 Gio d'espace disque. Heureusement, il a une version
gratuite et n'est pas trop contre-intuitif une fois que vous avez joué avec pendant un petit
moment. Vivado est disponible pour Windows et Linux mais pas pour macOS.
Arty Board
Créer un projet
1. Démarrer Vivado.
2. Sélectionnez "Créer un projet" sous "Démarrage rapide"(Quick Start).
3. Nom du projet: SE01 et assurez-vous que "Créer un sous-répertoire du projet" est
sélectionné.
4. Type de projet: "Projet RTL" et assurez-vous que "Ne pas spécifier les sources pour le
moment" est sélectionné.
5. Partie par défaut: Sélectionnez "Boards" puis choisissez "Arty" (Partie: xc7a35ticsg324-
1L). Si ce n'est pas dans la liste, vous devez quitter Vivado et installer le fichier de la carte
Arty.
6. Passez en revue le "Résumé du nouveau projet" (New Project Summary)et cliquez sur
"Terminer" (Finish).
Hello verilog
1. En haut à gauche de la fenêtre Vivado, sélectionnez "Ajouter des sources" (Add Sources
)sous "Gestionnaire de projets" (Project Manager).
2. Choisissez "Ajouter ou créer des sources de conception" et cliquez sur "Suivant".
3. Sélectionnez "Créer un fichier" au milieu de la boîte de dialogue.
4. Assurez-vous que le type de fichier est défini sur "Verilog" et nommez le fichier top.v,
puis cliquez sur "Terminer".
5. Dans la boîte de dialogue "Définir le module", cliquez sur "OK", puis sur "Oui" lorsque
vous y êtes invité.
La deuxième partie du module est l'endroit où nous écrivons notre logique. A chaque fois que
l'horloge se déclenche, nous vérifions l'état de l'interrupteur sw [0]: s'il est éteint, nous désactivons
le led [0]; sinon nous allumons la LED. 1'b0 est un littéral d'un bit avec la valeur 0. Vous verrez
plus d'exemples de littéraux plus loin dans ce tutoriel.
Enregistrez votre fichier en appuyant sur Ctrl-S ou en utilisant le bouton Enregistrer en haut à
gauche de la fenêtre de l'éditeur (oui, cela ressemble toujours à une disquette).
Vous pouvez utiliser Ctrl + / pour (dé) commenter la ligne en cours dans la fenêtre de l'éditeur
Vivado.
Fichier de contraintes
Un FPGA est très flexible. Vous pouvez connecter différents types d'entrées et de sorties aux
centaines de broches. Avant de synthétiser notre code, nous devons dire à Vivado comment
notre carte Arty est connectée. Vivado utilise des contraintes pour cartographier une référence,
telle que la led [0], à la norme de pin et d'E / S appropriée. Les contraintes fournissent également
des détails sur la source d'horloge, CLK, qui est fondamentale pour nos conceptions.
Même sur un PC rapide, tout ce processus prend quelques minutes, alors soyez patient.
Si vous fermez accidentellement une étape, vous pouvez trouver des commandes pour exécuter
les différentes étapes sur le côté gauche de la fenêtre Vivado.
Hello LED
Faites glisser le commutateur SW0 sur votre carte pour contrôler la LED verte LD4.
Partie 2:
Cette fonctionnalité n'est pas quelque chose que vous ne pourriez pas réaliser avec un
microcontrôleur. Cependant, cela vaut la peine de réfléchir à ce que vous avez fait ici. Vous avez
utilisé une logique programmable pour créer un circuit imprimé dans le FPGA lui-même: il n'y a
pas de CPU exécutant votre code. C'est comme si vous aviez câblé le circuit avec des composants
matériels discrets.
Pour voir une représentation visuelle de votre conception, vous pouvez visualiser le design
élaboré. Vous pouvez trouver ceci sous "Analyse RTL" sur le côté gauche de la fenêtre Vivado.
Vous pouvez voir les entrées d'horloge et de commutateur aller aux LED via quatre registres, qui
contiennent la valeur pour chaque LED.
NB Si vous êtes toujours dans Hardware Manager, vous pouvez revenir à votre code source
Verilog en sélectionnant "Gestionnaire de projets" en haut à gauche de la fenêtre Vivado.
2'b définit une valeur binaire de 2 bits: nous avons deux LED qui attendent chacune un bit, donc
une valeur de deux bits est appropriée ici. Vous pouvez également voir la notation pour
sélectionner une plage des sorties LED: led [1: 0] comprend led[0] et led[1].
Nous avons également quatre boutons-poussoirs sur le tableau; nous pouvons facilement les
ajouter à notre conception.
Pour inclure les boutons de commande, vous devez les ajouter à notre fichier de contraintes.
Ensuite, remplacez votre module supérieur par le suivant. Notez l'ajout des entrées de bouton
btn [3: 0], qui correspondent aux nouvelles entrées du fichier de contraintes:
SW0 contrôle tous les voyants, tandis que BTN0 sélectionne deux modèles de voyants différents.
Essayez vos propres combinaisons de commutateurs, boutons et voyants. Assurez-vous que vos
valeurs ont la même largeur que vos entrées et sorties, par exemple trois bits pour trois DEL: led
[3: 1] <= 3'b101;
Partie 1:
Dans ce TP nous allons realiser la simulation d’un compteur, l’énoncé qui suit va pas à pas vous
indiquer les diff érentes étapes à suivre pour réaliser cette simulation.
7. Branchez le Artix-7 avec ton PC Cliquez deux fois sur Program Device
Partie 2:
Il est parfois utile de pouvoir observer les signaux internes du FPGA en temps réel comme si on
utilisait un analyseur logique. Chez Xilinx, il existe un outil d’analyse qui utilise la liaison JTAG à
cet effet, c’est Vivado Analyzer. Il existe plusieurs méthodes pour l’utiliser : certaines nécessitent
la modification du code VHDL, d’autres sont totalement transparentes. Nous allons utiliser la
plus simple (sans modification du code VHDL).
C’est une méthode utile pour la mise au point mais elle consomme des ressources du FPGA
(notamment de la mémoire) et peut perturber le placement routage et donc le respect des
contraintes de timing. Dans le design final, il faut retirer ces outils d’analyse. Le but de ce TP est
de vous montrer l’utilisation de l’analyseur logique utilisable dans le FPGA (ILA : Integrated
Logic Analyzer) et configurable depuis Vivado. Cet analyseur vous permettra de réaliser la mise
au point de votre design directement dans le FPGA. Cela vous permettra de trouver des erreurs
impossibles à voir en simulation. En utilisant l’analyseur intégré ILA, vous pourrez voir
l’évolution des signaux internes de votre design dans le FPGA, donc en temps réel, sans modifier
votre code VHDL. Pour cela, Vivado doit insérer un composant (core) ILA après synthèse.
Fermez le Hardware Manager. Après synthèse, de nombreuses options sont apparues dans le
navigateur. Cliquez sur « Open Synthesized Design » :
La fenêtre Synthesized Design (design après synthèse) apparaît. Par défaut, elle montre
généralement l’intérieur du FPGA ce qui ne nous intéresse pas. Pour obtenir un schéma du
design synthétisé, sélectionnez le menu :
Le schéma du design apparaît à droite et les signaux internes à gauche (dans Nets) :
Pour zoomer sur le schéma, il suffit de cliquer en haut et à gauche de la zone à sélectionner, de
tirer vers le bas et à droite, puis de relacher le bouton de la souris :
ATTENTION : les signaux que vous voyez ici sont les signaux après synthèse et pas ceux déclarés dans votre
design. Le synthétiseur a optimisé le design et supprimé (ou fusionné) les signaux qu’il a estimé inutiles. Par
De ce fait, la sélection des signaux à debugger n’est pas toujours évidente car leur nom peut
changer. Nous allons utiliser le schéma pour nous aider. Par exemple, à la sortie du composant
reset_sync, vous pouvez sélectionner le signal sreset qui apparaît alors surligné dans la fenêtre
Netlist puis faire un clic droit et cliquer sur « Mark Debug » :
Arty est une plate-forme de développement prête à l'emploi conçue autour Artix-7 ™ (FPGA) de
Description
Ce simple projet de démonstration VGA démontre l'utilisation d'un VGA Pmod connecté aux
ports Pmod de l'Arty. Le comportement est le suivant:
Une boîte rebondissante et des barres de couleurs noir, blanc et multiples sont affichées
sur un moniteur VGA connecté.
Le VGA Pmod est contrôlé par l'Arty via les ports Pmod JB et JC.
La résolution de l'écran est configurable via le code HDL.
Conditions préalables
Matériel
Arty FPGA board
Pmod VGA
Câble micro-USB
Logiciel
Vivado Design Suite
Des versions plus récentes peuvent être utilisées, mais la procédure peut varier légèrement
1) Suivez le didacticiel Utiliser les projets de démonstration Github de Digilent. Il s’agit d’un
projet de conception HDL et, en tant que tel, ne prend pas en charge le SDK Vivado,
sélectionnez les options de didacticiel appropriées pour une conception uniquement
Vivado. Revenez à ce guide lorsque vous êtes invité à vérifier la configuration matérielle
et la configuration requises.
2) Une fois que vous avez généré votre fichier bit, assurez-vous que votre VGA Pmod est
branché sur les ports Pmod de votre Arty, JB et JC. Utilisez un câble VGA pour
connecter le Pmod VGA au port VGA de votre moniteur. Retournez au didacticiel
Github Projects pour terminer la programmation de votre tableau.
## Clock signal
##Switches
##RGB LEDs
#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L18N_T2_35 Sch=led0_b
#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L19N_T3_VREF_35 Sch=led0_g
#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L19P_T3_35 Sch=led0_r
#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1_b }]; #IO_L20P_T3_35 Sch=led1_b
#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1_g }]; #IO_L21P_T3_DQS_35 Sch=led1_g
#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1_r }]; #IO_L20N_T3_35 Sch=led1_r
#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2_b }]; #IO_L21N_T3_DQS_35 Sch=led2_b
#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2_g }]; #IO_L22N_T3_35 Sch=led2_g
#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2_r }]; #IO_L22P_T3_35 Sch=led2_r
#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3_b }]; #IO_L23P_T3_35 Sch=led3_b
#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3_g }]; #IO_L24P_T3_35 Sch=led3_g
#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3_r }]; #IO_L23N_T3_35 Sch=led3_r
##LEDs
set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { led }]; #IO_L24N_T3_35 Sch=led[4]
#set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_25_35 Sch=led[5]
#set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L24P_T3_A01_D17_14 Sch=led[6]
#set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L24N_T3_A00_D16_14 Sch=led[7]
##Buttons
#set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]; #IO_L6N_T0_VREF_16 Sch=btn[0]
#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]; #IO_L11P_T1_SRCC_16 Sch=btn[1]
#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2]
#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3]
##Pmod Header JA
#set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_0_15 Sch=ja[1]
#set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L4P_T0_15 Sch=ja[2]
#set_property -dict { PACKAGE_PIN A11 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L4N_T0_15 Sch=ja[3]
#set_property -dict { PACKAGE_PIN D12 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L6P_T0_15 Sch=ja[4]
#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L6N_T0_VREF_15 Sch=ja[7]
#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L10P_T1_AD11P_15 Sch=ja[8]
#set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L10N_T1_AD11N_15 Sch=ja[9]
#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_25_15 Sch=ja[10]
##Pmod Header JB
#set_property -dict { PACKAGE_PIN E15 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L11P_T1_SRCC_15 Sch=jb_p[1]
#set_property -dict { PACKAGE_PIN E16 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L11N_T1_SRCC_15 Sch=jb_n[1]
#set_property -dict { PACKAGE_PIN D15 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L12P_T1_MRCC_15 Sch=jb_p[2]
#set_property -dict { PACKAGE_PIN C15 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L12N_T1_MRCC_15 Sch=jb_n[2]
#set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L23P_T3_FOE_B_15 Sch=jb_p[3]
#set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L23N_T3_FWE_B_15 Sch=jb_n[3]
#set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L24P_T3_RS1_15 Sch=jb_p[4]
#set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L24N_T3_RS0_15 Sch=jb_n[4]
##Pmod Header JC
#set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { jc[0] }]; #IO_L20P_T3_A08_D24_14 Sch=jc_p[1]
#set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jc[1] }]; #IO_L20N_T3_A07_D23_14 Sch=jc_n[1]
#set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { jc[2] }]; #IO_L21P_T3_DQS_14 Sch=jc_p[2]
#set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { jc[3] }]; #IO_L21N_T3_DQS_A06_D22_14
##Pmod Header JD
#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L11N_T1_SRCC_35 Sch=jd[1]
#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L12N_T1_MRCC_35 Sch=jd[2]
#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L13P_T2_MRCC_35 Sch=jd[3]
#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L13N_T2_MRCC_35 Sch=jd[4]
#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L14P_T2_SRCC_35 Sch=jd[7]
#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L14N_T2_SRCC_35 Sch=jd[8]
#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15P_T2_DQS_35 Sch=jd[9]
#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L15N_T2_DQS_35 Sch=jd[10]
##USB-UART Interface
#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]; #IO_L19N_T3_VREF_16
Sch=uart_rxd_out
#set_property -dict { PACKAGE_PIN A9 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]; #IO_L14N_T2_SRCC_16
Sch=uart_txd_in
#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[0] }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0]
#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[1] }]; #IO_L18P_T2_A12_D28_14
Sch=ck_io[1]
#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[2] }]; #IO_L8N_T1_D12_14 Sch=ck_io[2]
#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io[3] }]; #IO_L19P_T3_A10_D26_14
Sch=ck_io[3]
#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io[4] }]; #IO_L5P_T0_D06_14 Sch=ck_io[4]
#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io[5] }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5]
#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[6] }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6]
#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[7] }];
#IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7]
#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io[8] }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8]
#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io[9] }]; #IO_L10P_T1_D14_14 Sch=ck_io[9]
#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[10] }]; #IO_L18N_T2_A11_D27_14
Sch=ck_io[10]
#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io[11] }]; #IO_L17N_T2_A13_D29_14
Sch=ck_io[11]
#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[12] }]; #IO_L12N_T1_MRCC_14
Sch=ck_io[12]
#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io[13] }]; #IO_L12P_T1_MRCC_14
Sch=ck_io[13]
#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[14] }]; #IO_0_35 Sch=ck_a[0]
#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_io[15] }]; #IO_L4P_T0_35 Sch=ck_a[1]
#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[16] }]; #IO_L4N_T0_35 Sch=ck_a[2]
#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[17] }]; #IO_L6P_T0_35 Sch=ck_a[3]
#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_io[18] }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4]
#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_io[19] }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5]
## ChipKit SPI
#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso
#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi
#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck
#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss
## ChipKit I2C
#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl
#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda
#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15
Sch=scl_pup
#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15
Sch=sda_pup
#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa
#set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { ck_rst }]; #IO_L16P_T2_35 Sch=ck_rst
#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col
#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15
#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs
#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14
Sch=qspi_dq[0]
#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14
Sch=qspi_dq[1]
#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14
Sch=qspi_dq[2]
#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14
Sch=qspi_dq[3]
##Power Measurements
#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15
Sch=ad_n[2]
#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15
Sch=ad_p[2]
#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15
Sch=ad_n[1]
#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15
Sch=ad_p[1]
#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15
Sch=ad_n[9]
#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15
Sch=ad_p[9]
#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15
Sch=ad_n[10]
#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15
Sch=ad_p[10]