FIFO (очередь) представляет собой одномерную таблицу памяти, которая, как правило, используется в цифровых схемах для передачи данных между двумя схемами с различными тактовыми сигналами. Кроме того, существуют и другие области применения. FIFO реализуется на основе памяти с двумя портами входа/выхода и двумя указателями, которые указывают адреса, по которым должны читаться/записываться данные.
Изначально указатели указывают на один и тот же адрес. При каждой записи/чтении данных указатель записи/чтения инкрементируется. Когда указатель достигает последнего адреса, происходит переполнение, и он начинает снова инкрементироваться с адреса 0.
Для мониторинга состояния памяти (какие адреса свободны) добавляется регистр (fifo_counter), который инкрементируется/декрементируется при записи/чтении. Соответственно, когда значение этого регистра становится равным объёму памяти, устанавливается флаг, указывающий, что память полностью занята. И наоборот, если значение fifo_counter равно 0, устанавливается флаг, указывающий, что вся память свободна.
module Queue (
clk,
rst,
wr_cs,
rd_cs,
data_in,
rd_en,
wr_en,
data_out,
empty
);
parameter DATA_WIDTH = 8;
parameter ADDR_WIDTH = 8;
parameter RAM_DEPTH = (1 << ADDR_WIDTH);
input clk;
input rst;
input wr_cs;
input rd_cs;
input rd_en;
input wr_en;
input [DATA_WIDTH-1:0] data_in;
output full;
output empty;
output [DATA_WIDTH-1:0] data_out;
reg [ADDR_WIDTH-1:0] wr_pointer;
reg [ADDR_WIDTH-1:0] rd_pointer;
reg [ADDR_WIDTH:0] status_cnt;
reg [DATA_WIDTH-1:0] data_out;
wire [DATA_WIDTH-1:0] data_ram;
assign full = (status_cnt == (RAM_DEPTH-1));
assign empty = (status_cnt == 0);
always @ (posedge clk or posedge rst)
begin
if (rst) begin
wr_pointer <= 0;
end else if (wr_cs && wr_en) begin
wr_pointer <= wr_pointer + 1;
end
end
always @ (posedge clk or posedge rst)
begin
if (rst) begin
rd_pointer <= 0;
end else if (rd_cs && rd_en) begin
rd_pointer <= rd_pointer + 1;
end
end
always @ (posedge clk or posedge rst)
begin
if (rst) begin
data_out <= 0;
end else if (rd_cs && rd_en) begin
data_out <= data_ram;
end
end
always @ (posedge clk or posedge rst)
begin
if (rst) begin
status_cnt <= 0;
end else if ((rd_cs && rd_en) && !(wr_cs && wr_en)
&& (status_cnt != 0)) begin
status_cnt <= status_cnt - 1;
end else if ((wr_cs && wr_en) && !(rd_cs && rd_en)
&& (status_cnt != RAM_DEPTH)) begin
status_cnt <= status_cnt + 1;
end
end
Стек в Verilog моделируется аналогично очереди, однако, как правило, запись/чтение из стека происходит через один и тот же интерфейс, поэтому логика входа/выхода будет отличаться.
module Stack (DataIO, Reset, Push, Pop, SP, Full, Empty, Err);
inout [3:0] DataIO;
input Push, Pop, Reset;
output Full, Empty, Err;
output [2:0] SP; // Указатель стека
reg Empty, Err;
reg Full;
reg [2:0] SP;
reg [3:0] Stack[7:0];
reg [3:0] DataR;
wire [3:0] #(0) DataIO = DataR;
always @ (negedge Pop)
begin
DataR = 4'bzzzz;
end
always @ (posedge Push or posedge Pop or posedge Reset)
begin
if (Reset == 1)
begin
DataR = 4'bzzzz;
SP = 3'b0;
Full = 0;
Empty = 0;
Err = 0;
end
if (Push == 1) begin
if (Empty == 1)
begin
Stack[SP] = DataIO;
Empty = 0;
if (Err == 1)
Err = 0;
end
else
if (Full == 1)
begin
Stack[SP] = DataIO;
Err = 1;
end
else
begin
SP = SP + 1;
Stack[SP] = DataIO;
if (SP == 3'b111)
Full = 1;
end
end
if (Pop == 1) begin
if ((SP == 3'b000) && (Empty != 1))
begin
DataR = Stack[SP];
Empty = 1;
end
else
if (Empty == 1)
begin
DataR = Stack[SP];
Err = 1;
end
else
begin
DataR = Stack[SP];
if (SP != 3'b000)
SP = SP - 1;
if (Err == 1) Err = 0;
if (Full == 1) Full = 0;
end
end
end
endmodule