Recettes RTL réutilisables¶
Ce sont des points de départ. Adaptez polarité, largeur, latence et interface.
Registre avec validation¶
process(clk_i)
begin
if rising_edge(clk_i) then
if reset_i = '1' then
data_q <= (others => '0');
elsif enable_i = '1' then
data_q <= data_i;
end if;
end if;
end process;
Compteur montant¶
process(clk_i)
begin
if rising_edge(clk_i) then
if reset_i = '1' then
count_q <= (others => '0');
elsif enable_i = '1' then
count_q <= count_q + 1;
end if;
end if;
end process;
Un unsigned revient naturellement à zéro après son maximum. Pour saturer, comparez avant l'incrément.
Compteur modulo-N avec tick¶
process(clk_i)
begin
if rising_edge(clk_i) then
tick_o <= '0';
if reset_i = '1' then
count_q <= 0;
elsif count_q = G_MODULUS - 1 then
count_q <= 0;
tick_o <= '1';
else
count_q <= count_q + 1;
end if;
end if;
end process;
Imposez G_MODULUS > 0 par assertion.
Synchroniseur deux bascules¶
signal sync_q : std_logic_vector(1 downto 0) := (others => '0');
attribute ASYNC_REG : string;
attribute ASYNC_REG of sync_q : signal is "TRUE";
process(clk_i)
begin
if rising_edge(clk_i) then
sync_q <= sync_q(0) & async_i;
end if;
end process;
sync_o <= sync_q(1);
Vérifiez le sens de concaténation : le bit 0 reçoit l'entrée puis le bit 1 reçoit l'ancien bit 0.
Détecteur de front montant¶
process(clk_i)
begin
if rising_edge(clk_i) then
if reset_i = '1' then
previous_q <= '0';
pulse_o <= '0';
else
pulse_o <= level_i and not previous_q;
previous_q <= level_i;
end if;
end if;
end process;
Le signal d'entrée doit déjà être synchrone.
Anti-rebond¶
Algorithme :
- Synchroniser l'entrée.
- Si l'échantillon égale la sortie acceptée, remettre le compteur à zéro.
- Sinon incrémenter.
- Au seuil, accepter le niveau et remettre le compteur à zéro.
À 100 MHz, 10 ms représentent 1 000 000 cycles. Exprimez la durée en cycles ou dérivez-la de G_CLOCK_HZ.
Registre à décalage¶
process(clk_i)
begin
if rising_edge(clk_i) then
if enable_i = '1' then
shift_q <= shift_q(shift_q'high - 1 downto 0) & serial_i;
end if;
end if;
end process;
Documentez le sens et l'extrémité contenant le bit le plus récent.
Encodeur de priorité¶
process(all)
begin
valid_o <= '0';
index_o <= (others => '0');
for index in request_i'reverse_range loop
if request_i(index) = '1' then
valid_o <= '1';
index_o <= to_unsigned(index, index_o'length);
exit;
end if;
end loop;
end process;
Le sens de boucle définit la priorité. Testez plusieurs requêtes simultanées.
Calcul d'une validation¶
Pour F_CLK et F_TICK :
Le résultat n'est exact que si la division tombe juste. Sinon, un accumulateur de phase fournit un rapport fractionnaire plus précis.
Handshake valid/ready¶
- Le producteur maintient
validet les données jusqu'au transfert. - Le consommateur lève
readylorsqu'il peut accepter. - Éviter toute boucle combinatoire via valid/ready.
Balayage sept segments¶
Associez un générateur de tick, un index de deux bits, un mux de chiffre, un décodeur hexadécimal et des activations one-hot actives à zéro. Un bref blanc entre changements peut supprimer le ghosting.
Tick UART¶
À 115 200 bauds et 100 MHz, le diviseur entier vaut environ 868. Calculez et documentez le débit réel. Pour la réception, créez souvent une validation 8× ou 16× et échantillonnez au centre du bit.
Règle de vérification¶
Chaque recette réutilisable doit tester reset, validation/maintien, minima, maxima, transition limite, génériques extrêmes et contrat de latence.