1、理论介绍
同步电路和异步电路
同步电路:所有触发器的时钟输入端都接同一个时钟脉冲,所有触发器状态的改变都与所加脉冲信号同步。
异步电路:电路没有统一的时钟。
FIFO介绍
先进先出存储器(first input first output),即先写入的数据被先读出,后写入的数据被后读出,一般使用同步fifo做缓存,使用异步fifo做跨时钟处理。
2、架构设计
同步FIFO
即只有一个时钟驱动,其模块框图如图1所示,FIFO中需要注意的地方是满空的判断,也就是在写满后不再写入,读空后不再读出,其内部主要电路框图如图2所示。
图1 同步FIFO模块
图2 同步FIFO内部主要电路框图
3、代码设计
一、同步FIFO代码设计
/***************************************
#
# Filename:fifo_sync.v
#
# Developer:annotater
# Description:---
# CreatTime:2021-08-11 19:22:09
#
***************************************/
module fifo_sync(
input clk_200m,
input sys_rst,
input wr_en,
input rd_en,
input[7:0] wr_data,
output reg[7:0] rd_data,
output full,
output empty
);
reg[7:0] fifo[7:0];//定义一个深度为8,位宽为8的FIFO
reg[3:0] wr_cnt,rd_cnt;//定义读指针和写指针,如果定义为[2:0],则会发现fifo不能完全写满,这里多定义一位,通过最高位来判断写满。
wire wr_e;
wire rd_e;
integer i;
always@(posedge clk_200m or posedge sys_rst)begin
if(sys_rst)begin
for(i=0;i<8;i=i+1)begin
fifo[i] <= 0;
end
wr_cnt <= 0;
rd_cnt <= 0;
rd_data <= 0;
end
else if(rd_e && wr_e)begin
fifo[wr_cnt[2:0]] <= wr_data;
rd_data <= fifo[rd_cnt[2:0]];
wr_cnt <= wr_cnt + 1;
rd_cnt <= rd_cnt + 1;
end
else if(rd_e)begin
rd_data <= fifo[rd_cnt[2:0]];
rd_cnt <= rd_cnt + 1;
end
else if(wr_e)begin
fifo[wr_cnt[2:0]] <= wr_data;
wr_cnt <= wr_cnt + 1;
end
end
assign full = (wr_cnt[3] ^ rd_cnt[3])&&(wr_cnt[2:0]==rd_cnt[2:0]);
assign empty = (wr_cnt[3:0] == rd_cnt[3:0]);
assign wr_e = wr_en && ~full;
assign rd_e = rd_en && ~empty;
endmodule
二、仿真代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/08/11 19:44:50
// Design Name:
// Module Name: tb_fifo_sync
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_fifo_sync();
reg clk_200m ;
reg sys_rst ;
reg wr_en ;
reg rd_en ;
reg[7:0] wr_data ;
wire[7:0] rd_data ;
wire full ;
wire empty ;
initial begin
clk_200m = 0;
sys_rst = 1;
wr_en = 0;
rd_en = 0;
wr_data = 0;
#10 sys_rst = 0;
forever #5 clk_200m = ~clk_200m;
end
initial begin
#200 wr_data = 8'b10101010;
wr_en = 1;
#180 wr_en = 0;
#10 rd_en = 1;
#100 rd_en = 0;
#30 wr_data = 8'b01010101;
wr_en = 1;
#180 wr_en = 0;
#10 rd_en = 1;
#100 rd_en = 0;
end
always@(posedge clk_200m) begin
if(wr_en)
#1 wr_data <= {wr_data[7:0],1'b0};
end
fifo_sync U_FIFO_SYNC(
.clk_200m ( clk_200m ), //i
.sys_rst ( sys_rst ), //i
.wr_en ( wr_en ), //i
.rd_en ( rd_en ), //i
.wr_data ( wr_data ), //i
.rd_data ( rd_data ), //o
.full ( full ), //o
.empty ( empty ) //o
);
endmodule
4、仿真分析
可以看到深度写完8位后,full信号拉高,这时候wr_en为高,但是也没有继续写入,后rd_en拉高,可以看到数据读出的顺序为写入的顺序,也就是先入先出,读完8位数据后,显示读空(日如图3),这时候再次写入,可发现规律是一样的(如图4),说明设计的FIFO重复读写时没有问题的。
图3
图4