多比特信号的跨时钟域的处理

再理解了很多的跨时钟域的处理后,整理一个自己的思路,然后记录一下

(36条消息) 多bit信号的跨时钟域处理_凡尘若夜的博客-CSDN博客_多bit跨时钟域为参考,其中大部分的理解也是根据这篇文章。

 1.用后缀_t表示数据发送端,用后缀_r表示数据接收端。发送端时钟用tclk表示,接收端时钟用rclk表示

2.当有数据需要发送的时候,将t_rdy信号拉高为1,同时再rclk的时钟域下,打两拍与rclk进行时钟同步,得到r_rdy_clk。

3.当r_rdy_clk为高时,说明数据在rclk中处于安全地带,所以这个时候可以开始读取数据,读取数据的同时,将r_ack置1。

4.同样的,将r_ack信号打两拍同步t_clk时钟域,在同步过来时,将t_rdy拉低,表示数据传输完成

5.在数据的准备信号t_rdy(t_rdy_clk)拉低时,将r_ack拉低,r_ack_tclk也紧跟着被拉低,握手完成,等待下一次的数据传输

关于多比特信号传输的代码:

module async_hand(
    //clk i
    rstn_i,
    clk_i,
    in_vld,
    din,
    in_ack,

    //clk o
    rstn_o,
    clk_o,
    out_vld,
    dout,
    out_ack
);

input wire rstn_i;
input wire clk_i;
input wire in_vld;
input wire [7:0] din;
output wire in_ack;

input wire rstn_o;
input wire clk_o;
output reg out_vld;
output reg [7:0]dout ;
input wire out_ack;

wire din_cap;
reg [7:0] din_r;
reg in_vld_lev;
reg in_vld_lev_1;
reg in_vld_lev_2;
reg in_vld_lev_rd;
wire in_vld_lev_2_rise;
wire dout_cap;
reg vld_sync;

reg vld_sync_1;
reg vld_sync_2;
reg vld_sync_rd;
wire vld_sync_2_rise;

assign din_cap = in_ack & in_vld;

always@(posedge clk_i) begin
    if(din_cap)
    din_r <= din;
end

always@(posedge clk_i or negedge rstn_i)begin
    if(!rstn_i)
    in_vld_lev <= 1'b0;
    else if(din_cap == 1)
    in_vld_lev <= 1'b1;
    else if(in_vld_lev) begin
        if(vld_sync_2_rise)
        in_vld_lev <= 1'b0;
    end
end

always@(posedge clk_o or negedge rstn_o) begin
    if(!rstn_o) 
    in_vld_lev_1 <= 1'b0;
    else
    in_vld_lev_1 <= in_vld_lev;
end

always@(posedge clk_o or negedge rstn_o) begin
    if(!rstn_o)
    in_vld_lev_2 <= 1'b0;
    else
    in_vld_lev_2 <= in_vld_lev_1;
end

always@(posedge clk_o or negedge rstn_o) begin
    if(!rstn_o)
    in_vld_lev_rd <= 1'b0;
    else
    in_vld_lev_rd <= in_vld_lev_2;
end

assign in_vld_lev_2_rise = in_vld_lev_2 & (!in_vld_lev_rd);//跨时钟已经完成,剩下的该数据的取样了,上升沿已经抓到,将这个信号和vld和ack信号关联起来,该dout的操作了

always@(posedge clk_o or negedge rstn_o) begin
    if(!rstn_o)
    out_vld <= 1'b0;
    else if(in_vld_lev_2_rise)
    out_vld <= 1'b1;
    else if(out_ack)
    out_vld <= 1'b0;
end

assign dout_cap = out_vld & out_ack;

always@(posedge clk_o)begin //or negedge rstn_o) begin
    if(dout_cap == 1)
    dout <= din_r;
end

always@(posedge clk_o or negedge rstn_o) begin
    if(!rstn_o)
    vld_sync <= 1'b0;
    else if(dout_cap)
    vld_sync <= 1'b1;
    else if(vld_sync) begin
        if((!out_vld) && (!in_vld_lev_2))
        vld_sync <= 1'b0;
    end
end

always @(posedge clk_i or negedge rstn_i) begin
    if(!rstn_i)
    vld_sync_1 <= 0;
    else
    vld_sync_1 <= vld_sync;
end

always @(posedge clk_i or negedge rstn_i) begin
    if(!rstn_i)
    vld_sync_2 <= 0;
    else
    vld_sync_2 <= vld_sync_1;
end

always@(posedge clk_i or negedge rstn_i) begin
    if(!rstn_i)
    vld_sync_rd <= 0;
    else
    vld_sync_rd <= vld_sync_2;
end

assign vld_sync_2_rise = vld_sync_2 & (!vld_sync_rd);
assign in_ack = (!in_vld_lev) & (!vld_sync_2) ;//在clk_i的时钟域中,由clk_i到clk_o的传输和由clk_o到clk_i的传输均完成,需要新的信号了。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值