设计要求
实现2的幂深度的异步fifo,要求空满状态监测,空时不可读,满时不可写。
设计思路
1.端口与中间信号定义
input wclk ,wrstn,wr,wdata //write时钟域中时钟信号,复位信号,wr使能信号,wdata写入数据
input rclk ,rrstn,rd //read时钟域中的时钟,复位信号,读使能信号
output full empty rdata // 满/空标志 ,rd后读出的数据。
middle signal addr_w[depth:0] addr_r[depth:0] //写地址,读地址,位宽多一位
gray_addr_w gray_addr_r //将写读地址转化为格雷码,位宽同addr,多一位判断
reg [width-1:0] regs [fifo_depth-1:0] // 寄存器regs由fifo_depth个小寄存器构成,每个小寄存器的位宽是width (fifo_depth == 2^depth)
2.参数化
深度即是fifo中寄存数据个数,宽度即是数据位宽,用传参的方式定义。即module name #(parameter ....)();
3.addr
写操作在wclk进行,每次wr有效,addr_w自加一。读操作同理。
4.gray
异步fifo涉及两个时钟域,为减少资源使用的同时兼顾数据传输的稳定性,选择格雷码配合数据传输。题目要求2的幂的深度,故可以直接使用格雷码,若有其他要求,可在格雷码的基础上进行删改或者查表,来保证二级制码转换而成的码具有格雷码的特性,
将addr转化为格雷码:gray <= (addr >> 1 ) ^ addr;
值得注意的是,原addr最高位仅用于判断空满状态,地址由其他位存储。转换后的gray仅仅用于比对空满状态,无存储地址的功能。
也就是说,地址由原时钟域的addr存储,同时在原时钟域产生一个addr的格雷码,传输到另一时钟域,再与另一时钟域的addr所产生的gray比对,来判断空满状态。
若两格雷码完全相同,即可判断为空状态,若两格雷码前两位相反,其余位相同,可判断为满状态。
5.gray传输
格雷码可由组合逻辑产生,亦可在always块中由寄存器存储。值得注意的是,若由组合逻辑产生,在跨时钟传输之前,需要在原时钟域中打一拍以消除因由组合逻辑延迟产生的毛刺。之后在通过二级同步器以传入另一时钟域
6.regs赋值与读取
integer i; //位宽为32,需注意
always@(posedge wclk or negedge wrstn)
begin
if(!wrstn)
begin
for(i=0;i<fifo_depth;i=i+1)
begin
regs[i] <= 0;
end
end
else if (allow_wr) //即判断状态为非满:assign allow wr =wr && full;
begin
regs[addr_w[depth-1:0]] <= wdata;
end
end
rdata同理。
总结
addr负责给地址,gray负责判断空满,rags负责寄存数据,wdata写入,rdata读出,完成异步fifo功能。
仿真效果
vcs+verdi:
spyglass lint && cdc:
warning均为 ignored