FIFO IP Core
- 先进先出的缓存器
- 常常被用于数据的缓存,或者高速异步数据交互(跨时钟信号传递)
- 和RAM和ROM的区别是没有地址线,无法指定地址
- 写时钟(Write Clock Domain),读时钟
- 写复位(wr_rst),读复位,整体复位
- 写使能(wr_en),读使能
- 写满标志(full),读空标志(empty)
- almost_full:快要满了,almost_empty:快要空了
- Prog_full:可编程写满,prog_empty:可编程读空(根据自己设置的数据个数拉高或拉低)
- wr_ack:写反馈(对写使能的应答) valid:读出的数据是一个稳定有效的值
- overflow:写溢出 underflow:读空(下溢出)
- wr_data_count: Fifo中储存的写数据的数量 rd_data_count:储存的读数据的数量
- prog_full_thresh_assert: 动态修改prog_full的值
- prog_full_thresh_negate:门限值失效
FIFO IP Core的设置
实验结构:
创建工程和设计文件ip_fifo,添加FIFO IP Core
选择异步时钟的BRAM(这样后面的读写数据量才能设置,同步时钟的默认相等)
设置读写宽度和深度,取消复位引脚
勾选Almost Full Flag & Almost Empty Flag
勾选读写数据量的计数
如何抓取上升沿/下降沿?
信号en: _________|————
reg d0 = en 当前时刻的值
reg d1 = d0 前一时刻的值
当d1 = 0, d0 = 1时 说明是上升沿 == ~d1&d0 为真
当d1 = 1, d0 = 0时 说明是下降沿 == ~d0&d1 为真
写模块 fifo_wr
输入信号:时钟,复位,将空,将满
输出信号:写使能,写数据
module fifo_wr(
input clk,
input rst,
input almost_empty,
input almost_full,
output reg fifo_wr_en,
output reg[7:0] fifo_wr_data
);
endmodule
抓取almost_empty信号上升沿
reg almost_empty_cur;
reg almost_empty_pre;
wire syn;
// assign 过程赋值,右边的值发送变化会重新赋值
assign syn = ~almost_empty_pre & almost_empty_cur;
always @(posedge clk or posedge rst) begin
if(rst) begin
almost_empty_cur <= 1'b0;
almost_empty_pre <= 1'b0;
end
else begin
almost_empty_cur <= almost_empty;
almost_empty_pre <= almost_empty_cur;
end
end
不能对数据立刻赋值,fpga内部不一样准备好了,需要延迟等待一段时间,这样的需求可以用状态机完成
状态机
6.3 Verilog 状态机 | 菜鸟教程 (runoob.com)
这里有三个状态,延迟等待10个周期
所以定义:
reg [1:0] state;
reg [3:0] delay_cnt;
状态转换:
// 状态机
reg [1:0] state;
// 延迟数
reg [3:0] delay_cnt;
always @(posedge clk or posedge rst) begin
if(rst) begin
fifo_wr_en <= 1'b0;
fifo_wr_data <= 8'd0;
state <= 2'b0;
delay_cnt <= 4'b0;
end
else begin
case(state)
2'd0:begin
if(syn) state <= 2'b1;
else state <= 2'b0;
end
2'd1: begin
if(delay_cnt == 4'd10) begin
fifo_wr_en <= 1'b1;
delay_cnt <= 4'd0;
state <= 2'd2;
end
else delay_cnt <= delay_cnt + 1'b1;
end
2'd2: begin
if(almost_full) begin
fifo_wr_en <= 1'b0;
fifo_wr_data <= 8'd0;
state <= 2'b0;
end
else begin
fifo_wr_data <= fifo_wr_data + 1'd1;
end
end
default:
state <= 2'b0;
endcase
end
end
读模块fifo_rd
将写模块中的写使能变为读使能
写满判断变为读空判断
去掉写数据
module fifo_rd(
input clk,
input rst,
input almost_empty,
input almost_full,
input [7:0] fifo_rd_data,
output reg fifo_rd_en
);
reg almost_full_cur;
reg almost_full_pre;
wire syn;
// assign 过程赋值,右边的值发送变化会重新赋值
assign syn = ~almost_full_pre & almost_full_cur;
always @(posedge clk or posedge rst) begin
if(rst) begin
almost_full_cur <= 1'b0;
almost_full_pre <= 1'b0;
end
else begin
almost_full_cur <= almost_full;
almost_full_pre <= almost_full_cur;
end
end
// 状态机
reg [1:0] state;
// 延迟数
reg [3:0] delay_cnt;
always @(posedge clk or posedge rst) begin
if(rst) begin
fifo_rd_en <= 1'b0;
state <= 2'b0;
delay_cnt <= 4'b0;
end
else begin
case(state)
2'd0:begin
if(syn) state <= 2'b1;
else state <= 2'b0;
end
2'd1: begin
if(delay_cnt == 4'd10) begin
delay_cnt <= 4'd0;
state <= 2'd2;
end
else delay_cnt <= delay_cnt + 1'b1;
end
2'd2: begin
if(almost_empty) begin
fifo_rd_en <= 1'b0;
state <= 2'b0;
end
else fifo_rd_en <= 1'b1;
end
default:
state <= 2'b0;
endcase
end
end
endmodule
例化顶层模块 fifo_ip
module ip_fifo(
input sys_clk,
input sys_rst
);
wire almost_empty;
wire almost_full;
wire fifo_wr_en;
wire[7:0] fifo_wr_data;
fifo_wr fifo_wr_u(
.clk (sys_clk),
.rst (sys_rst),
.almost_empty (almost_empty),
.almost_full (almost_full),
.fifo_wr_en (fifo_wr_en),
.fifo_wr_data (fifo_wr_data)
);
wire fifo_rd_en;
fifo_rd fifo_rd_u(
.clk (sys_clk),
.rst (sys_rst),
.almost_empty (almost_empty),
.almost_full (almost_full),
.fifo_rd_en (fifo_rd_en)
);
wire [7:0] dout;
wire full;
wire empty;
wire [7:0] rd_data_count;
wire [7:0] wr_data_count;
fifo_generator_0 fifo_generator_0_u(
.wr_clk(sys_clk), // input wire wr_clk
.rd_clk(sys_clk), // input wire rd_clk
.din(fifo_wr_data), // input wire [7 : 0] din
.wr_en(fifo_wr_en), // input wire wr_en
.rd_en(fifo_rd_en), // input wire rd_en
.dout(dout), // output wire [7 : 0] dout
.full(full), // output wire full
.almost_full(almost_full), // output wire almost_full
.empty(empty), // output wire empty
.almost_empty(almost_empty), // output wire almost_empty
.rd_data_count(rd_data_count), // output wire [7 : 0] rd_data_count
.wr_data_count(wr_data_count) // output wire [7 : 0] wr_data_count
);
endmodule
约束
set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sys_clk }]; #IO_L11P_T1_SRCC_35 Sch=sysclk
set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { sys_rst}];
综合
ILA
10个探针,设置位宽:
例化ILA添加到顶层模块ip_fifo
ila_0 your_instance_name (
.clk(sys_clk), // input wire clk
.probe0(fifo_wr_en), // input wire [0:0] probe0
.probe1(fifo_rd_en), // input wire [0:0] probe1
.probe2(full), // input wire [0:0] probe2
.probe3(almost_full), // input wire [0:0] probe3
.probe4(fifo_wr_data), // input wire [7:0] probe4
.probe5(dout), // input wire [7:0] probe5
.probe6(rd_data_count), // input wire [7:0] probe6
.probe7(wr_data_count), // input wire [7:0] probe7
.probe8(empty), // input wire [0:0] probe8
.probe9(almost_empty) // input wire [0:0] probe9
);
下载验证
生成bitstream,连接开发板,观看ila波形