再理解了很多的跨时钟域的处理后,整理一个自己的思路,然后记录一下
以(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的传输均完成,需要新的信号了。