ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

日常记录(94)fifo深度、CDC、寄存器锁存器区别

2022-06-11 13:33:50  阅读:266  来源: 互联网

标签:存器 CDC fifo valid rclk logic ready input 时钟


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

  1. 单bit信号,两级dff(filp flop)
    对建立和保持时间进行满足。
    从不稳定到稳定的时间一般是小于时钟周期。
    在下一个时钟周期再对Q1进行采样,就能得到的一个稳定的、确定的值Q2
    https://blog.csdn.net/qq_40268672/article/details/123009355

  2. 格雷码
    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)
  1. 异步握手
    https://blog.csdn.net/qq_40268672/article/details/123078718
  • 两级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信号,发送结束。
image
代码:

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有