设计任务:
本章节将会在已经完成的 IP 核读、写模块基础上添加 FIFO 接口,对于读、 写端都会添加一组 FIFO,其中包括命令端 FIFO和数据端FIFO。
设计目的:
之前的课程我们完成了 IP 核的读、写控制,但是无论是读还是写,每次都只能发送一次命令和一次突发的数据,也就是说在读或者写的过程中,当再来一次读或者写的命令时,我们的控制器是没有办法执行的,为了解决掉这个问题,我 们可以加存储器将没有办法及时执行的命令和数据缓存起来,当本次操作结束后, 可以从缓冲器内取下一次需要执行的命令和数据,这样就可以防止命令和数据丢失。
FIFO 接口实现:
1、总体框架介绍
我们先给出加完 FIFO 的总体框架,然后再细分析每个环节,添加 FIFO 的结构框架如图 1 所示。如图 1 所示,我们添加了 4 个模块,其中 rd_data_fifo_ctrl 为 读数据的缓冲 fifo、rd_cmd_fifo_ctrl 为读命令的缓冲 fifo、wr_data_fifo_ctrl 为写 数据的缓冲 fifo、wr_cmd_fifo_ctrl 为写命令的缓冲 fifo。 当读、写命令FIFO 中有命令时,对应的 empty 信号将会为低电平,因此我们可以将读、写命令FIFO的empty信号取反后作为仲裁模块的rd_req和wr_req。同时,仲裁模块输出的读、写开始信号可以作为读、写命令 FIFO 的读使能,根 据仲裁模块输出的读、写开始信号可以读出读、写命令 FIFO 内的命令、地址、 突发长度等,A7_rd_ctrl 和 A7_wr_ctrl 模块根据命令 FIFO 读出的信息可以进行相应的操作。 A7_rd_ctrl 模块读出的数据可以存入到 rd_data_fifo_ctrl,因此 rd_data_valid 可以作为 rd_data_fifo_ctrl 的写使能,rd_data_128bit 可以作为 rd_data_fifo_ctrl 的 写数据。A7_wr_ctrl 模块输入的数据可以从 rd_data_fifo_ctrl 中读出,因此 data_req 可以作为 wr_data_fifo_ctrl 的读使能,data_128bit 可以作为 wr_data_fifo_ctrl 的读数据。
2、各个模块变量说明
下面对四个新加入的模块的端口进行说明,首先我们先对读端的命令 FIFO 和数据 FIFO 进行说明。为了方便我们区分读写模块,此处我用 p1 代表读,p2 代表写。
A7 的 DDR3 IP 核外围添加 FIFO 接口控制器的代码实现
module fifo(
input wire init_calib_complete,
input wire ui_clk,
//p1_data
input wire p1_rd_clk,
input wire p1_rd_en,
input wire rd_data_valid,
input wire [127:0] rd_data_128bit,
output wire p1_rd_empty,
output wire p1_rd_full,
output wire [127:0] p1_rd_data,
output wire p1_rd_count,
//p1_cmd
input wire p1_cmd_clk,
input wire p1_cmd_en,
input wire [2:0] p1_cmd_intr,
input wire [6:0] p1_cmd_bl,
input wire [27:0] p1_cmd_addr,
input wire rd_cmd_start,
output wire p1_cmd_empty,
output wire p1_cmd_full,
output wire [2:0] rd_cmd_intr,
output wire [27:0] rd_cmd_addr,
output wire [6:0] rd_cmd_bl,
//p2_data
input wire p2_wr_clk,
input wire p2_wr_en,
input wire [127:0] p2_wr_data,
input wire [15:0] p2_wr_mask,
input wire data_req,
output wire [15:0] wr_mask,
output wire [127:0] data_128bit,
output wire p2_wr_empty,
output wire p2_wr_full,
output wire p2_wr_count,
//p2_cmd
input wire p2_cmd_clk,
input wire p2_cmd_en,
input wire [2:0] p2_cmd_intr,
input wire [6:0] p2_cmd_bl,
input wire [27:0] p2_cmd_addr,
input wire wr_cmd_start,
output wire p2_cmd_empty,
output wire p2_cmd_full,
output wire [2:0] wr_cmd_intr,
output wire [27:0] wr_cmd_addr,
output wire [6:0] wr_cmd_bl
);
cmd_fifo cmd_fifo_inst_wr (
.rst(~init_calib_complete), // input wire rst
.wr_clk(p2_cmd_clk), // input wire wr_clk
.rd_clk(ui_clk), // input wire rd_clk
.din({p2_cmd_intr,p2_cmd_bl,p2_cmd_addr}), // input wire [37 : 0] din
.wr_en(p2_cmd_en), // input wire wr_en
.rd_en(wr_cmd_start), // input wire rd_en
.dout({wr_cmd_intr,wr_cmd_bl,wr_cmd_addr}), // output wire [37 : 0] dout
.full(p2_cmd_full), // output wire full
.empty(p2_cmd_empty), // output wire empty
.wr_rst_busy(), // output wire wr_rst_busy
.rd_rst_busy() // output wire rd_rst_busy
);
wr_data_fifo wr_data_fifo_inst (
.rst(~init_calib_complete), // input wire rst
.wr_clk(p2_wr_clk), // input wire wr_clk
.rd_clk(ui_clk), // input wire rd_clk
.din({p2_wr_mask,p2_wr_data}), // input wire [143 : 0] din
.wr_en(p2_wr_en), // input wire wr_en
.rd_en(data_req), // input wire rd_en
.dout({wr_mask,data_128bit}), // output wire [17 : 0] dout
.full(p2_wr_full), // output wire full
.empty(p2_wr_empty), // output wire empty
.wr_data_count(p2_wr_count), // output wire [6 : 0] wr_data_count
.wr_rst_busy(), // output wire wr_rst_busy
.rd_rst_busy() // output wire rd_rst_busy
);
cmd_fifo cmd_fifo_inst_rd (
.rst(~init_calib_complete), // input wire rst
.wr_clk(p1_cmd_clk), // input wire wr_clk
.rd_clk(ui_clk), // input wire rd_clk
.din({p1_cmd_intr,p1_cmd_bl,p1_cmd_addr}), // input wire [37 : 0] din
.wr_en(p1_cmd_en), // input wire wr_en
.rd_en(rd_cmd_start), // input wire rd_en
.dout({rd_cmd_intr,rd_cmd_bl,rd_cmd_addr}), // output wire [37 : 0] dout
.full(p1_cmd_full), // output wire full
.empty(p1_cmd_empty), // output wire empty
.wr_rst_busy(), // output wire wr_rst_busy
.rd_rst_busy() // output wire rd_rst_busy
);
rd_data_fifo rd_data_fifo_inst (
.rst(~init_calib_complete), // input wire rst
.wr_clk(ui_clk), // input wire wr_clk
.rd_clk(p1_rd_clk), // input wire rd_clk
.din(rd_data_128bit), // input wire [127: 0] din
.wr_en(rd_data_valid), // input wire wr_en
.rd_en(p1_rd_en), // input wire rd_en
.dout(p1_rd_data), // output wire [127 : 0] dout
.full(p1_rd_full), // output wire full
.empty(p1_rd_empty), // output wire empty
.rd_data_count(p1_rd_count), // output wire [6 : 0] rd_data_count
.wr_rst_busy(), // output wire wr_rst_busy
.rd_rst_busy() // output wire rd_rst_busy
);
endmodule