Le module Verilog ci-dessous définit une FIFO asynchrone avec des paramètres configurables pour la largeur des données et la profondeur. Le mode FWFT (First Word Fall Through) est activé, et la conversion en code Gray est employée pour gérer les pointeurs entre domaines d'horloge. La mémoire est implémentée comme une RAM à double port, avec des signaux de statut "plein" et "vide" générés par comparaison des pointeurs synchronisés.
// Module de FIFO asynchrone en Verilog `timescale 1ns/1ps module Async_FIFO_Module #( parameter DATA_WIDTH = 8, // Largeur des données parameter DEPTH_POWER = 3 // Exposant pour la profondeur : 2**DEPTH_POWER ) ( input async_reset, // Réinitialisation asynchrone input write_clock, // Horloge d'écriture input write_enable, // Requête d'écriture input [DATA_WIDTH-1:0] data_in, // Données à écrire output reg full_flag, // Indicateur FIFO pleine output reg [DEPTH_POWER-1:0] write_count, // Compteur d'écriture input read_clock, // Horloge de lecture input read_enable, // Requête de lecture output [DATA_WIDTH-1:0] data_out, // Données lues output reg empty_flag, // Indicateur FIFO vide output reg [DEPTH_POWER-1:0] read_count // Compteur de lecture );
// Signaux internes
wire [DEPTH_POWER-1:0] addr_write, addr_read;
wire [DEPTH_POWER:0] bin_next_write, gray_next_write;
wire [DEPTH_POWER:0] bin_next_read, gray_next_read;
wire full_condition, empty_condition;
reg [DATA_WIDTH-1:0] memory [0:(1<<depth_power addr_write="bin_counter_write[DEPTH_POWER-1:0];" address_diff="" always="" assign="" async_reset="" begin="" bin_counter_read="" bin_counter_write="" bin_next_write="bin_counter_write" dans="" data_in="" data_out="memory[addr_read];" des="" donn="" du="" else="" end="" g="" gray_next_write="bin_next_write" gray_pointer_read="" gray_pointer_write="" if="" la="" m="" memory="" negedge="" or="" pointeurs="" read_clock="" reg="" signal="" sortie="" sync_read_ptr1="" sync_read_ptr2="" sync_write_ptr1="" sync_write_ptr2="" synchronisation="" tampon="" write_clock="" write_enable="">> 1);
assign full_condition = (gray_next_write == {~sync_write_ptr2[DEPTH_POWER:DEPTH_POWER-1], sync_write_ptr2[DEPTH_POWER-2:0]});
always @(posedge write_clock or negedge async_reset) begin
if (!async_reset) begin
bin_counter_write <= 0;
gray_pointer_write <= 0;
end else begin
bin_counter_write <= bin_next_write;
gray_pointer_write <= gray_next_write;
end
end
always @(posedge write_clock or negedge async_reset) begin
if (!async_reset) begin
full_flag <= 0;
end else begin
full_flag <= full_condition;
end
end
// Génération du signal "vide"
assign addr_read = bin_counter_read[DEPTH_POWER-1:0];
assign bin_next_read = bin_counter_read + (!empty_flag && read_enable);
assign gray_next_read = bin_next_read ^ (bin_next_read >> 1);
assign empty_condition = (gray_next_read == sync_read_ptr2);
always @(posedge read_clock or negedge async_reset) begin
if (!async_reset) begin
bin_counter_read <= 0;
gray_pointer_read <= 0;
end else begin
bin_counter_read <= bin_next_read;
gray_pointer_read <= gray_next_read;
end
end
always @(posedge read_clock or negedge async_reset) begin
if (!async_reset) begin
empty_flag <= 1;
end else begin
empty_flag <= empty_condition;
end
end
// Calcul des compteurs
always @(*) begin
if (!async_reset) begin
address_diff = 0;
end else if (addr_write > addr_read) begin
address_diff = addr_write - addr_read;
end else begin
address_diff = (1 << (DEPTH_POWER+1)) - addr_read + addr_write;
end
end
always @(posedge write_clock or negedge async_reset) begin
if (!async_reset) begin
write_count <= 0;
end else begin
write_count <= address_diff[DEPTH_POWER-1:0];
end
end
always @(posedge read_clock or negedge async_reset) begin
if (!async_reset) begin
read_count <= 0;
end else begin
read_count <= address_diff[DEPTH_POWER-1:0];
end
end
endmodule </depth_power>
</div>Le fichier de test ci-dessous simule le comportement de la FIFO asynchrone avec des horloges indépendantes et des scénarios d'écriture/lecture. Les signaux de contrôle sont générés pour tester les états plein, vide, et les opérations simultanées. Le compteur de test définit des périodes d'écriture seule, suivies de lecture, puis de lecture/écriture concurrentes pour valider la robustesse de la conception.
<div>```
// Banc de test pour FIFO asynchrone
`timescale 1ns/1ps
module Async_FIFO_Testbench();
// Signaux de test
reg clk_write, clk_read, reset_n;
reg [7:0] data_to_write;
reg wr_req, rd_req;
// Génération des horloges et réinitialisation
initial begin
reset_n = 0;
#2000 reset_n = 1;
end
initial begin
clk_write = 0;
clk_read = 0;
end
always #5 clk_write = ~clk_write;
always #10 clk_read = ~clk_read;
// Instance du module FIFO
Async_FIFO_Module #(
.DATA_WIDTH(8),
.DEPTH_POWER(4)
) fifo_inst (
.async_reset(reset_n),
.write_clock(clk_write),
.write_enable(wr_req),
.data_in(data_to_write),
.full_flag(),
.write_count(),
.read_clock(clk_read),
.read_enable(rd_req),
.data_out(),
.empty_flag(),
.read_count()
);
// Logique de contrôle des écritures
reg [10:0] counter_write;
always @(posedge clk_write or negedge reset_n) begin
if (!reset_n) begin
counter_write <= 0;
end else if (counter_write == 2000) begin
counter_write <= 0;
end else begin
counter_write <= counter_write + 1;
end
end
always @(posedge clk_write or negedge reset_n) begin
if (!reset_n) begin
data_to_write <= 0;
wr_req <= 0;
end else if ((counter_write >= 1 && counter_write <= 21) || (counter_write >= 1000 && counter_write <= 1090)) begin
data_to_write <= counter_write[7:0];
wr_req <= 1;
end else begin
data_to_write <= 0;
wr_req <= 0;
end
end
// Logique de contrôle des lectures
always @(posedge clk_read or negedge reset_n) begin
if (!reset_n) begin
rd_req <= 0;
end else if (counter_write[9]) begin
rd_req <= 1;
end else begin
rd_req <= 0;
end
end
endmodule