作为一个大一年级学过C语言的本科僧,我很早就知道“队列” 的概念,它描述了一种先进先出的数据结构(First In First Out, FIFO),现在要在FPGA上实现同样的功能,下面介绍思路。
数据结构
采用二维数组的形式
reg [B - 1:0] array_reg [2**W-1:0];
采用循环计数的数字作为“指针”。
难点 :判断读、写指针重合的时候谁在前面。
解决难点的方法:用w_ptr_succ
和r_ptr_succ
两个“未来”的指针判断下一步谁在前谁在后。
设计思路:Moore型状态机。
Verilog实现方法
学校发的板子是Digilent的Basys II,这个板子只支持ISE,我使用了ISE Webpack(再穷也要用正版的/大哭(还好Webpack免费还装着方便))
吐槽一句,ISE在2k屏上糊的惨不忍睹且没有解决方法,只有接上1080p的显示器才能勉强用的舒服。
module fifo
#(parameter B = 8, W = 4)(
input wire clk, reset,
input wire rd, wr,
input wire [B-1:0] w_data,
output wire empty , full,
output wire [B-1:0] r_data
);
reg [B - 1:0] array_reg [2**W-1:0];
reg [W - 1:0] w_ptr_reg, w_ptr_next, w_ptr_succ;
reg [W - 1:0] r_ptr_reg, r_ptr_next, r_ptr_succ;
reg full_reg, empty_reg, full_next, empty_next;
wire wr_en;
always @(posedge clk)
if (wr_en)
array_reg[w_ptr_reg] <= w_data;
assign r_data = array_reg[r_ptr_reg];
assign wr_en = wr & (~full_reg);
initial
begin
w_ptr_reg <= 0;
r_ptr_reg <= 0;
full_reg <= 1'b0;
empty_reg <= 1'b1;
end
always @(posedge clk , posedge reset)
if(reset)
begin
w_ptr_reg <= 0;
r_ptr_reg <= 0;
full_reg <= 1'b0;
empty_reg <= 1'b1;
end
else
begin
w_ptr_reg <= w_ptr_next;
r_ptr_reg <= r_ptr_next;
full_reg <= full_next;
empty_reg <= empty_next;
end
always @*
begin
w_ptr_succ = w_ptr_reg + 1;
r_ptr_succ = r_ptr_reg + 1;
w_ptr_next = w_ptr_reg;
r_ptr_next = r_ptr_reg;
full_next = full_reg;
empty_next = empty_reg;
case ({wr, rd})
2'b01:
if(~empty_reg)
begin
r_ptr_next = r_ptr_succ;
full_next = 1'b0;
if(r_ptr_succ == w_ptr_reg)
empty_next = 1'b1;
end
2'b10:
if(~full_reg)
begin
w_ptr_next = w_ptr_succ;
empty_next = 1'b0;
if (w_ptr_succ == r_ptr_reg)
full_next = 1'b1;
end
2'b11:
begin
w_ptr_next = w_ptr_succ;
r_ptr_next = r_ptr_succ;
end
2'b00:;
endcase
end
assign full = full_reg;
assign empty = empty_reg;
endmodule
仿真效果
使用写入和读取简单字符的形式写testbench,如下
`timescale 1ns / 1ps
module test_fifo;
// Inputs
reg clk;
reg reset;
reg rd;
reg wr;
reg [7:0] w_data;
// Outputs
wire empty;
wire full;
wire [7:0] r_data;
// Instantiate the Unit Under Test (UUT)
fifo uut (
.clk(clk),
.reset(reset),
.rd(rd),
.wr(wr),
.w_data(w_data),
.empty(empty),
.full(full),
.r_data(r_data)
);
always
begin
clk = ~clk;
#10;
end
always
begin
{wr, rd} <= 2'b10;
w_data <= "A";
#20;
{wr, rd} <= 2'b10;
w_data <= "B";
#20;
{wr, rd} <= 2'b10;
w_data <= "C";
#20;
{wr, rd} <= 2'b10;
w_data <= "D";
#20;
{wr, rd} <= 2'b01;
#20;
{wr, rd} <= 2'b01;
#20;
{wr, rd} <= 2'b01;
#20;
{wr, rd} <= 2'b01;
#20;
end
initial begin
// Initialize Inputs
clk = 0;
reset = 0;
rd = 0;
wr = 0;
w_data = 0;
//reset = 1;
//#10;
//reset = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
end
endmodule
需要说明的是,FIFO一定要初始化,要么在使用之前先reset,要么在module中直接用initial初始化一下。
仿真效果图:
说明这个程序能够完成FIFO的功能