Types et numeric_std¶
VHDL est fortement typé. Cette rigueur peut sembler lourde au début, mais elle évite des erreurs silencieuses de largeur, de signe et d'interprétation particulièrement dangereuses en matériel.
Types logiques IEEE¶
std_logic possède neuf valeurs :
| Valeur | Signification |
|---|---|
U |
Non initialisé |
X |
Valeur inconnue forcée ou conflit de pilotes |
0, 1 |
Niveaux logiques forcés |
Z |
Haute impédance |
W |
Inconnue faible |
L, H |
Bas/haut faibles |
- |
Indifférent |
Dans un RTL synchrone normal, les signaux internes doivent finir à 0 ou 1. Une valeur U ou X révèle utilement un défaut d'initialisation, de reset, d'affectation ou de pilotes multiples.
Warning
Ne masquez pas les inconnues par une conversion imprudente en entier. Corrigez leur cause.
Vecteur, non signé ou signé ?¶
| Type | Interprétation | Usage conseillé |
|---|---|---|
std_logic_vector |
Bits sans valeur numérique | Bus, champs codés, ports |
unsigned |
Entier binaire positif ou nul | Compteurs, adresses, tailles |
signed |
Entier en complément à deux | Données signées et DSP |
Choisissez le type qui exprime l'intention. Un std_logic_vector ne dit pas si son motif binaire est signé.
signal raw_i : std_logic_vector(7 downto 0);
signal count_u : unsigned(7 downto 0);
signal sample_s : signed(7 downto 0);
count_u <= unsigned(raw_i);
sample_s <= signed(raw_i);
Ces opérations réinterprètent les bits sans changer leur taille.
Carte des conversions¶
u8 <= to_unsigned(integer_value, u8'length);
s8 <= to_signed(integer_value, s8'length);
integer_value := to_integer(u8);
integer_value := to_integer(s8);
slv <= std_logic_vector(u8);
slv <= std_logic_vector(s8);
u8 <= unsigned(slv);
s8 <= signed(slv);
Le signe doit toujours être explicite
signed(x"FF") vaut −1 sur 8 bits, tandis que unsigned(x"FF") vaut 255. Les bits sont identiques, leur sens arithmétique ne l'est pas.
Règles de largeur¶
Une addition ne fournit pas automatiquement un bit supplémentaire de retenue. Étendez d'abord les opérandes :
full_sum <= ('0' & a_i) + ('0' & b_i);
sum_o <= full_sum(a_i'range);
carry_o <= full_sum(full_sum'high);
Utilisez resize :
wide_u <= resize(narrow_u, wide_u'length); -- extension par zéro
wide_s <= resize(narrow_s, wide_s'length); -- extension du signe
small <= resize(wide_u, small'length); -- troncature volontaire
Lors d'une réduction de largeur, choisissez explicitement :
- retour modulo/troncature ;
- saturation au minimum ou maximum ;
- signalement du dépassement ;
- arrondi puis troncature.
Entiers et plages¶
Les entiers conviennent aux génériques, modèles de référence et compteurs à plage claire :
Une plage contrainte documente l'intention et peut réduire le matériel, mais son dépassement provoque une erreur en simulation. Pour les chemins de données bit-exacts, unsigned ou signed rend souvent la largeur plus évidente.
Tableaux¶
type sample_array_t is array (natural range <>) of signed(15 downto 0);
signal history : sample_array_t(0 to 7);
type word_array_t is array (natural range <>) of std_logic_vector(7 downto 0);
signal registers : word_array_t(0 to 15);
Le symbole <> définit un tableau non contraint réutilisable avec plusieurs longueurs.
Enregistrements¶
type stream_t is record
valid : std_logic;
ready : std_logic;
data : std_logic_vector(7 downto 0);
end record;
Les enregistrements regroupent les signaux liés et facilitent l'évolution des interfaces internes. Des ports à plat restent souvent plus simples au sommet du FPGA pour les contraintes XDC.
Énumérations et sous-types¶
type state_t is (IDLE, LOAD, RUN, DONE);
signal state_q, state_d : state_t := IDLE;
subtype byte_t is std_logic_vector(7 downto 0);
subtype percentage_t is natural range 0 to 100;
Vivado choisit normalement l'encodage des états. Écrivez le comportement avec les noms, sans supposer leur motif binaire.
Virgule fixe¶
Pour commencer :
- Positionner la virgule binaire sur papier.
- Stocker les bits dans
signedouunsigned. - Élargir volontairement produits et additions.
- Définir des fonctions nommées d'arrondi et de saturation.
En Q1.7 signé sur 8 bits, l'entier stocké 64 représente 0,5 car 64 / 128 = 0,5. Le paquetage IEEE fixed_pkg devient utile dans les projets plus vastes.
Règle sur les paquetages arithmétiques¶
Utilisez ieee.numeric_std. Évitez les anciens paquetages Synopsys non normalisés :
std_logic_arithstd_logic_unsignedstd_logic_signed
Les mélanger à numeric_std crée des surcharges ambiguës et du code non portable.
Liste de contrôle¶
- Chaque vecteur possède-t-il un sens et un ordre de bits documentés ?
- Les nombres signés et non signés ont-ils le bon type ?
- Les opérandes sont-ils étendus avant une opération nécessitant un bit de plus ?
- Chaque troncature, saturation ou retour modulo est-il volontaire ?
- Les unités physiques sont-elles visibles dans les noms ou les types ?
- Un générique peut-il créer une plage nulle ou négative ? Ajouter une assertion.