日常记录(94)fifo深度、CDC、寄存器锁存器区别
作者:互联网
fifo深度计算
fifo深度的计算只能是大致考虑,如果说burst传输中,两个时钟的开始边沿不一致,或者是背靠背传输过程中,读数据也存在最差的情况(而非计算过程中使用的平均速度),则fifo深度可能不太准确吧?
https://www.cnblogs.com/shadow-fish/p/13447277.html
https://mp.weixin.qq.com/s/jfUyTUWW4i1aVTzKJjqZhg
1. burst传输
写时钟50MHZ,读时钟20MHZ(读或写一位数据只需要一个时钟),将1000个数据顺利的进行写读传输,计算FIFO缓存深度。
首先,写时钟为50MHZ,则写一个数据需要时间t=1/50MHZ=20ns。
其次,读时钟为20MHZ,则读一个数据需要时间t1=1/20MHZ=50ns。
则在2us时间内,能读取数据个数N=20us/50ns=400。
也就是说在20us内,可以写入1000个数据,同时读出400个数据,还剩600个数据需要缓存到FIFO中,因此FIFO的深度至少为600。(不考虑计算上的失误)。
2. 背靠背传输
上面的例子为按时钟等间隔读写操作,那么非等间隔时钟读写呢?
写时钟为80MHZ,读时钟为50MHZ,每100个时钟写入40个数据,每10个时钟读出8个数据,随机写入,计数此时的FIFO深度?
因为只有100个时钟周期写入40个数据—可以理解为:40个时钟写入40个数据,剩余60时钟进入IDLE状态。因此考虑最坏情况:获得最大写入速率,最小读出速率。背靠背传输:首先60个IDLE,40个data,40个data,60个IDLE。
因此连续写入80个数据所需要的最快时间T=80*(1/80M)=1000us
读出一位数据所需时间t=(10/8)*(1/50M)=25ns
则在T时间内,读出数据个数N=1000/25=40
所有FIFO的深度为80-40=40
假设FIFO的写时钟为wclk,读时钟为rclk,在FIFO输入侧,每B个写时钟,写入A个数据,在读数据侧,每Y个时钟读出X个数据,问FIFO设置为多少FIFO不会溢出?
考虑最坏情况(背对背),B就用不到了:
2A - [(2A*(1 / wclk))/ (1 / rclk)] * (X / Y)
CDC(Clock Domain Crossing)跨时钟域同步
https://blog.csdn.net/qq_40268672
-
单bit信号,两级dff(filp flop)
对建立和保持时间进行满足。
从不稳定到稳定的时间一般是小于时钟周期。
在下一个时钟周期再对Q1进行采样,就能得到的一个稳定的、确定的值Q2
https://blog.csdn.net/qq_40268672/article/details/123009355 -
格雷码
https://blog.csdn.net/qq_40268672/article/details/123018083
要采样的是一个多bit的跨时钟域信号,比如4bit信号,那么由于建立时间和保持时间的违例,虽然在打两拍之后可以得到一个稳定的数据,但该数据的每一个bit都不一定是正确的,所以其可能的值有2^4=16种,这显然是无法接受的,因此,对于多比特信号的跨时钟域处理,不能照搬。
- 二进制转格雷码
逻辑左移异或
assign gray_code = (bnary >> 1) ^ bnary;
- 格雷码转二进制
高位向低位按位异或
bin[i] = ^(gray >> i)
- 两级dff缺陷。
当发送方的时钟比接收方的时钟快时,有可能出现信号有效时间过段,接收方采样不到的情况。 - 同步握手。
发送方要发送数据的时候,就拉高VALID信号,同时把要发送的数据放到数据总线上,接受方看到VALID信号为高,并且自己也有时间接受数据,于是拉高READY信号,表示数据已经被接收,发送方看到接受方已完成数据的接收,于是拉低VALID信号,同时接收方也拉低READY信号,一次握手完成。 - 异步握手。
为了防止亚稳态的出现,发送发的VALID信号同步到接收方的时钟域中,经过几个周期的同步,容易在发送VALID信号还未置低的情况下,又被接收方采样到,认为是新的数据开始。
了解决这个问题,不检测VALID的高电平信息,转而检测VALID的上升沿信息,同理READY信号同步的时候也这么做。
在send时钟域sclk的上升沿放置发送数据,置位VALID信号。VALID信号通过valid_ff,同步到receive时钟域rclk,然后产生pulse,当检测pulse为1,读取数据到dout,然后产生ready信号。ready信号被发送端时钟域通过ready_ff进行同步,然后产生pulse,检测到pulse为1后置低valid信号,发送结束。
代码:
sender.sv
`timescale 1ns / 1ps
module sender(
input logic sclk,
input logic rst,
input logic start,
input logic [31:0] data,
output logic valid,
output logic [31:0]sdata,
input logic ready //从另一个时钟域来的ready信号
);
logic ready_ff1;
logic ready_ff2;
logic ready_ff3;
logic pulse;
assign pulse=ready_ff2&&~ready_ff3; //检测read_ff3上升沿
always_ff@(posedge sclk,posedge rst)
if(rst)
begin
ready_ff1<=0;
ready_ff2<=0;
ready_ff3<=0;
end
else
begin
ready_ff1<=ready;
ready_ff2<=ready_ff1;
ready_ff3<=ready_ff2;
end
//valid
always_ff@(posedge sclk,posedge rst)
if(rst)
valid<=0;
else if(start)
valid<=1;
else if(pulse)
valid<=0;
//sdata
always_ff@(posedge sclk,posedge rst)
if(rst)
sdata<=0;
else if(start)
sdata<=data;
endmodule
receiver.sv
`timescale 1ns / 1ps
module receiver(
input logic rclk,
input logic rst,
input logic [31:0]sdata, //来自另一个时钟域的sdata
input logic valid, //来自另一个时钟域的valid
output logic ready,
output logic [31:0] dout
);
logic valid_ff1;
logic valid_ff2;
logic valid_ff3;
logic pulse;
//valid信号同步至rclk时钟域
always_ff@(posedge rclk)
begin
valid_ff1<=valid;
valid_ff2<=valid_ff1;
valid_ff3<=valid_ff2;
end
//pluse
always_comb
begin
pulse=valid_ff2&&~valid_ff3; //检测valid_ff3的上升沿
end
//dout
always_ff@(posedge rclk,posedge rst)
if(rst)
dout<=0;
else if(pulse)
dout<=sdata;
//ready
always_ff@(posedge rclk,posedge rst)
if(rst)
ready<=0;
else if(pulse)
ready<=1;
else
ready<=0;
endmodule
handshake.sv
`timescale 1ns / 1ps
module handshake(
input logic rclk,
input logic sclk,
input logic rst,
input logic start,
input logic [31:0] data
);
logic ready;
logic valid;
logic [31:0] sdata;
logic [31:0] dout;
sender U1(.*);
// input logic sclk,
// input logic rst,
// input logic start,
// input logic [31:0] data,
// output logic valid,
// output logic [31:0]sdata,
// input logic ready //从另一个时钟域来的ready信号
// );
receiver U2(.*);
// input logic rclk,
// input logic rst,
// input logic [31:0]sdata, //来自另一个时钟域的sdata
// input logic valid, //来自另一个时钟域的valid
// output logic ready,
// output logic [31:0] dout
endmodule
test_tb.sv
`timescale 1ns / 1ps
module test_tb;
parameter PERIOD_S = 10;
parameter PERIOD_R = 17;
logic rclk;
logic sclk;
logic rst;
logic start;
logic [31:0] data;
//rclk
initial begin
rclk=0;
forever begin
#(PERIOD_R/2) rclk=~rclk;
end
end
//sclk
initial
begin
sclk=0;
forever
begin
#(PERIOD_S/2) sclk=~sclk;
end
end
//rst
initial
begin
rst=1;
#50
rst=0;
end
//start
initial
begin
start=0;
#(100+$random%100)
start=1;
#(PERIOD_S)
start=0;
end
//data
initial
begin
data=23;
end
handshake U(.*);
// input logic rclk,
// input logic sclk,
// input logic rst,
// input logic start,
// input logic [31:0] data
// );
endmodule
寄存器锁存器区别
https://www.csdn.net/tags/MtjaUg2sNDIxODgtYmxvZwO0O0OO0O0O.html
(1)寄存器是同步时钟控制,而锁存器是电位信号控制。锁存器一般由电平信号控制,属于电平敏感型。寄存器一般由时钟信号信号控制,属于边沿敏感型。
(2)寄存器的输出端平时不随输入端的变化而变化,只有在时钟有效时才将输入端的数据送输出端(打入寄存器),而锁存器的输出端平时总随输入端变化而变化,只有当锁存器信号到达时,才将输出端的状态锁存起来,使其不再随输入端的变化而变化
STA和后仿
http://www.javashuo.com/article/p-vtjzpnhb-th.html
随着设计向65nm以下的工艺发展,只用静态分析工具将无法精确验证串扰等动态效应。通过动态时序分析与静态时序分析相结合可以验证时序逻辑的建立/保持时间,并利用动态技术来解决串扰效应、动态模拟时钟网络等问题。
标签:存器,CDC,fifo,valid,rclk,logic,ready,input,时钟 来源: https://www.cnblogs.com/bai2022/p/16365686.html