双fifo流水线实现3x1024数组数据按列相加

本文转载自:尤老师FPGA的CSDN博客

Vivado版本:2019.2 MATLAB Modelsim版本:Modelsim SE-64 10.7
实验内容:双fifo流水线实现3x1024数组数据按列相加

FIFO,First Input First Output,既先入先出,也是一种存储器。本质上还是RAM,外面加了一层地址管理,这样使得FIFO没有地址线,使得使用起来非常方便。缺点是只能顺序写入和顺序读出,不能随机访问。如果数据把FIFO写满了,数据就不能继续写入,原来的数据也不会被覆盖;读取数据也只能读取一遍,读空后继续进行读操作,数据会一直保持最后一个读出的数据。
通过官方指导手册查看时序细节以及IP核配置内容。
打开vivado软件,新建一个工程,配置芯片为xc7z020clg400-1:


进入工程,选择IP Catalog:在这里插入图片描述
在IP Catalog界面搜索框中输入FIFO,可以看到有多种接口的FIFO,如AXI接口和AXI_Stream接口,这里选择FIFO Generator:

双击打开配置FIFO界面,左侧可以看到配置内容对应的接口,有FIFO读写使能信号、读写数据接口、空满信号以及时钟和复位,右侧可以配置模块的接口类型,以及时钟结构,可选的有Common Clock(读写同步时钟)与Independent Clocks(读写异步时钟)以及选用的存储类型,并且在下方表中可以查看各个存储类型支持的功能。
这里接口保持默认为Native,FIFO配置为Common Clock Block RAM:

FIFO读模式有两种,Standard FIFO与First Word Fall Through,Standard模式是相对于读使能,输出数据有1拍延时;FWFT模式特点是相对读使能可以0延时读出数据。
各自对应的时序为:

上图虽然是Independent Clock,但是读取时序与Common Clock一致。由上图所示,Standard模式下拉高rd_en读使能信号后,rd_clk下一拍时钟的上升沿数据线才会出数据,empty读空信号会在最后一个数据被读取时一同拉高,almost_empty在倒数第二个数据被读取时拉高。

由上图所示,在First Word Fall Through模式下,第一个数据被提前放在dout线上,拉高rd_en后,并不需要等待一拍,empty信号也是在最后一个数据被读完时才拉高,almost_empty信号在读取最后一个数据时拉高。
再来看一下写的关键时序:写入并没有模式限制,在wr_en信号为高时,数据有效,在wr_clk作用下依次写入FIFO中,当fifo写满时,full满信号拉高。

在Native Ports标签下配置读模式为First Word Fall Through模式,写入位宽为16位,写入深度为1024,读取位宽为16位,读取深度自动生成为1024,ECC与输出寄存器不勾选,复位接口也不需要,该复位是复位一下接口,并不会清空FIFO中的内容,如果想清空fifo,可以使用读空的方式。

Status Flags标签页下配置状态接口,默认接口中已经有空满信号,这些按设计添加。

Data Counts配置数据计数器,Common Clock下读和写使用一个Data Count,如果是独立时钟,读和写就可以使用各自时钟域对应的计数器。通过官方手册得到,计数器会比读写使能延迟两个时钟。

Summary标签显示配置的内容:

注意:如果读写位宽不匹配,如写入读出比例为1:4,数据会先放在高位后放在低位,此时需要连续写入4拍,读出只需要1拍时钟。如图:

写入与读出比例为4:1,则会先读出高位数据,后读出低位数据,此时写入一拍数据,读出需要4拍才能完全读完。如图:

了解了FIFO的工作时序与配置内容,生成IP核,通过调用两次方式组装流水线。
目的是将3行1024列数组按列相加,数据是一行一行输入的,通过fifo1进行缓存,当缓存完1行数据后,开始读,读取的数据送入fifo2中进行缓存;当fifo2缓存完1行数据时,输入数据为第3行的第1列数据,fifo1中数据为第2行数据,fifo2中为第1行数据,如此就将连续输入的三行数据分离,然后逐列相加即可。时序如下:

按照时序图编写控制代码。并编写一个仿真激励,使用随机数据作为输入,验证流水线是否正常工作。
仿真结果如下:

可以看到在输入第三行数据(row=2)时,加法器启动,输出三行逐列相加的结果,时序与设计一致。
查看累加结果,也是正确的。

实验完成。

附:控制器代码:

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/06/04 11:19:25
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//

module top(
input wire sclk,
input wire rst_n,
input wire in_valid,
input wire [15:0] in_data,
output reg out_valid,
output reg [15:0] out_data
);

//---------------------------------------------------------------
// Define Signal
//---------------------------------------------------------------
reg [11:0] cnt_fifo_wr = 0;
wire [ 1:0] row;
wire [ 9:0] col;

wire fifo1_wr_en;
wire [15:0] fifo1_wr_data;
reg fifo1_rd_en;
wire [15:0] fifo1_rd_data;
wire fifo1_full;
wire fifo1_empty;
wire [10:0] fifo1_data_count;

wire fifo2_wr_en;
wire [15:0] fifo2_wr_data;
reg fifo2_rd_en;
wire [15:0] fifo2_rd_data;
wire fifo2_full;
wire fifo2_empty;
wire [10:0] fifo2_data_count;

reg [15:0] sum = 0;

//---------------------------------------------------------------
// Main Program
//---------------------------------------------------------------
always @(posedge sclk) begin
if (rst_n == 1’b0) begin // reset
cnt_fifo_wr <= 0;
end
else if (in_valid == 1’b1) begin
cnt_fifo_wr <= cnt_fifo_wr + 1;
end
else begin
cnt_fifo_wr <= 0;
end
end
assign row = cnt_fifo_wr[11:10];
assign col = cnt_fifo_wr[9:0];

assign fifo1_wr_en = in_valid;
assign fifo1_wr_data = in_data;
fifo_generator_0 fifo1 (
.clk (sclk ), // input wire clk
.din (fifo1_wr_data ), // input wire [15 : 0] din
.wr_en (fifo1_wr_en ), // input wire wr_en
.rd_en (fifo1_rd_en ), // input wire rd_en
.dout (fifo1_rd_data ), // output wire [15 : 0] dout
.full (fifo1_full ), // output wire full
.empty (fifo1_empty ), // output wire empty
.data_count (fifo1_data_count ) // output wire [10 : 0] data_count
);

always @(posedge sclk) begin
if (rst_n == 1’b0) begin // reset
fifo1_rd_en <= 0;
end
else if (fifo1_empty == 1’b1) begin
fifo1_rd_en <= 0;
end
else if (cnt_fifo_wr == 12’d1023) begin
fifo1_rd_en <= 1;
end
end

assign fifo2_wr_en = fifo1_rd_en;
assign fifo2_wr_data = fifo1_rd_data;
fifo_generator_0 fifo2 (
.clk (sclk ), // input wire clk
.din (fifo2_wr_data ), // input wire [15 : 0] din
.wr_en (fifo2_wr_en ), // input wire wr_en
.rd_en (fifo2_rd_en ), // input wire rd_en
.dout (fifo2_rd_data ), // output wire [15 : 0] dout
.full (fifo2_full ), // output wire full
.empty (fifo2_empty ), // output wire empty
.data_count (fifo2_data_count ) // output wire [10 : 0] data_count
);

always @(posedge sclk) begin
if (rst_n == 1’b0) begin // reset
fifo2_rd_en <= 0;
end
else if (fifo2_empty == 1’b1) begin
fifo2_rd_en <= 0;
end
else if (cnt_fifo_wr == 12’d2047) begin
fifo2_rd_en <= 1;
end
end

always @(posedge sclk) begin
if (rst_n == 1’b0) begin // reset
out_valid <= 0;
out_data <= 0;
end
else if (fifo2_rd_en == 1’b1 && in_valid == 1’b1) begin
out_valid <= 1;
out_data <= in_data + fifo1_rd_data + fifo2_rd_data;
end
else begin
out_valid <= 0;
out_data <= 0;
end
end

endmodule

附:仿真激励代码:

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/06/04 11:35:58
// Design Name:
// Module Name: tb_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//

module tb_top (); /* this is automatically generated */

// clock
reg clk;
initial begin
clk = 'b0;
forever #(5) clk = ~clk;
end

// synchronous reset
reg rst_n;
initial begin
rst_n <= 'b0;
repeat(100)@(posedge clk);
rst_n <= 'b1;
end

// (*NOTE*) replace reset, clock, others

reg in_valid;
reg [15:0] in_data;
wire out_valid;
wire [15:0] out_data;

reg [11:0] cnt_in_valid = 0;
wire [ 1:0] row;
wire [ 9:0] col;

always @(posedge clk) begin
if (rst_n == 1'b0) begin // reset
in_valid <= 0;
in_data <= 0;
cnt_in_valid<= 0;
end
else if (cnt_in_valid <= 'd3071) begin
in_valid <= 1;
in_data <= {$random}%1024;
cnt_in_valid<= cnt_in_valid + 1;
end
else begin
in_valid <= 0;
in_data <= 0;
cnt_in_valid<= cnt_in_valid;
end
end

assign row = cnt_in_valid[11:10];
assign col = cnt_in_valid[9:0];

top inst_top (
.sclk (clk),
.rst_n (rst_n),
.in_valid (in_valid),
.in_data (in_data),
.out_valid (out_valid),
.out_data (out_data)
);
endmodule

链接:https://pan.baidu.com/s/1qMD6M91oXo_Ls920Y0fLqA
提取码:02ko

最新文章

最新文章