Lire un petit design RTL complet
Relire un compteur de paquets de l'interface jusqu'aux cas limites, puis relier le code au matériel attendu.
Le besoin
Le module suivant reçoit un flux avec valid, ready, data et last. Il additionne les octets d'un paquet. Lors du transfert du dernier octet, il publie la somme et lève o_sum_valid pendant un cycle.
Un transfert a lieu uniquement lorsque i_valid && o_ready vaut 1 sur un front montant. Le module accepte un octet à chaque cycle.
module packet_sum #(
parameter int unsigned DATA_WIDTH = 8,
parameter int unsigned SUM_WIDTH = 16
) (
input logic i_clk,
input logic i_rst,
input logic i_valid,
output logic o_ready,
input logic [DATA_WIDTH-1:0] i_data,
input logic i_last,
output logic [SUM_WIDTH-1:0] o_sum,
output logic o_sum_valid
);
logic [SUM_WIDTH-1:0] accumulator_q;
logic [SUM_WIDTH-1:0] extended_data;
always_comb begin
extended_data = '0;
extended_data[DATA_WIDTH-1:0] = i_data;
o_ready = 1'b1;
end
always_ff @(posedge i_clk) begin
if (i_rst) begin
accumulator_q <= '0;
o_sum <= '0;
o_sum_valid <= 1'b0;
end else begin
o_sum_valid <= 1'b0;
if (i_valid && o_ready) begin
if (i_last) begin
o_sum <= accumulator_q + extended_data;
o_sum_valid <= 1'b1;
accumulator_q <= '0;
end else begin
accumulator_q <= accumulator_q + extended_data;
end
end
end
end
endmoduleRelire l'interface avant le corps
La largeur de somme doit être au moins égale à la largeur de donnée. Le module ne connaît pas la longueur maximale du paquet, donc il ne peut pas garantir l'absence de débordement. Ce comportement doit être accepté, signalé par une sortie, ou limité par le cahier des charges.
o_ready vaut toujours 1. Il n'y a donc aucune contre-pression. Si la sortie devait attendre un consommateur, l'architecture devrait stocker un résultat en attente et abaisser o_ready au bon moment.
Suivre un cas à la main
Pour un paquet 3, 5, 2 avec last sur 2 :
- après
3, l'accumulateur vaut 3 ; - après
5, il vaut 8 ; - sur le dernier transfert,
o_sumreçoit8 + 2; o_sum_validvaut 1 pendant le cycle suivant le front ;- l'accumulateur revient à zéro pour le paquet suivant.
Les affectations non bloquantes expliquent pourquoi o_sum utilise l'ancienne valeur de accumulator_q, puis ajoute la donnée courante.
Chercher les cas limites
Une revue utile pose au moins ces questions :
- Que se passe-t-il pour un paquet d'un seul octet ?
- Les entrées sont-elles ignorées lorsque
i_validvaut 0 ? - Le reset abandonne-t-il proprement un paquet incomplet ?
- Deux paquets peuvent-ils se suivre sans cycle vide ?
- Que se passe-t-il si la somme dépasse
SUM_WIDTH? - Le paramètre
SUM_WIDTH < DATA_WIDTHest-il interdit ?
Un testbench doit couvrir ces cas, pas seulement un paquet nominal.
Relier le code au circuit
Le circuit contient un registre accumulateur, un additionneur, un registre de sortie et un bit de validation. Le chemin combinatoire principal passe par l'addition avant l'accumulateur ou la sortie. Si la fréquence demandée est trop élevée, il faudra revoir la largeur, le pipeline ou le protocole.
À retenir
- La revue commence par le contrat des ports et du protocole.
- Un exemple nominal ne suffit pas, les bornes et séquences consécutives comptent.
- Les tailles de paramètres doivent avoir une relation valide.
- Les affectations non bloquantes utilisent les anciennes valeurs des registres.
- Lire le RTL revient aussi à prévoir registres, opérateurs et chemins de timing.
📝 Tester mes connaissances - Quiz du chapitre