知识点(其他跨时钟域)
跨时钟域包含哪些情况?
PS:由于FIFO涉及的问题较多,单独在另一篇帖子。
跨时钟域包括:慢到快与快到慢两种
一、慢到快
1、单bit:两级同步器。
2、多bit:延迟采样法。
(1)有din_en,对din_en打拍使得打拍后的使得din_en上升沿在数据的中间,进行边沿检测,检
测到上升沿时采样数据。
(2)无din_en,在快时钟域时慢时钟进行打拍,并检测慢时钟的上升沿。
(3)两者频率差距很大的情况下,需要通过计数来确定采样的时刻
module mult_bit_sync(
input clk1,//慢时钟
input rst_n,
input clk2,//快时钟
input [7:0]din,//假定数据宽度为7,
input din_vaild,
output [7:0] dout,
output dout_vaild
);
// 由于clk1与clk2差距很大,所以clk2直接对clk1打拍
reg clk1_reg,clk1_reg1,clk1_reg2;
always@(posedge clk2 or negedge rst_n)begin
if(!rst_n)
begin
clk1_reg <= 0;
clk1_reg1 <= 0;
clk1_reg2 <= 0;
end
else
begin
clk1_reg <= clk1;
clk1_reg1 <= clk_reg;
clk1_reg2 <= clk_reg1;
end
end
assign clk1_pos = ~clk1_reg2&&clk1_reg1;
//实行计数在中间采集
reg [5:0] cnt;
always@(posedge clk2 or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(clk1_pos&&din_en)
cnt <= 0;
else if(cnt!=6'b111111)
cnt <= cnt + 1;
else
cnt <= cnt;
end
reg [7:0]dout_reg;
reg din_reg;
always@(posedge clk2 or negedge rst_n)begin
if(!rst_n)
dout_reg <= 0;
else if(din_en&&cnt == 'd33)
dout_reg <= din;
else
dout_reg <= dout_reg;
end
always@(posedge clk2 or negedge rst_n)begin
if(!rst_n)
dout_en_reg <= 0;
else if(din_en&&cnt == 'd33)
dout_en_reg <= 1;
else
dout_en_reg <= 0;
end
assign dout_vaild = dout_en_reg;
assign dout = dout_reg;
(4)对于两者频率较小的情况需要对慢时钟域的数据进行缓存处理后再进行采样
二、快到慢
1、脉冲同步器
(1)若需同步脉冲宽度不一致,需要采用握手的方式。
//当有脉冲输入或者及有请求或应答信号时,表示同步正忙。
//当有脉冲输入且同步不忙时,写时钟域产生req信号,相当于展宽了写时钟域的脉冲信号。
//读时钟域采到req信号,产生读时钟域的脉冲
//读时钟域脉冲被写时钟域采到,产生应答信号,并且拉低req信号。
module sync_pluse(
input rst_req,
input rst_dst,
input sync_pluse,
input clk_req,
input clk_dst,
output dst_pluse,
output sync_fail//同步正忙指示
);
reg sync_req,sync_ack;
assign sync_idle = ~(sync_req|sync_ack);
always@(posedge clk_req or negedge rst_req)begin
if(!rst_req)
sync_fail <= 0;
else if(sync_pluse&&(~sync_idle))
sync_fail <= 1;
else
sync_fail <= 0;
end
always@(posedge clk_req or negedge rst_req)begin
if(!rst_req)
sync_req <= 0;
else if(sync_pluse&&sync_idle)
sync_req <= 1;
else if(sync_ack_req)
sync_req <= 0;
end
reg dst_req_reg,dst_req_reg1,sync_req_dst,sync_ack;
always@(posedge clk_dst or negedge rst_dst)begin
if(!rst_dst)
begin
dst_req_reg <= 0;
dst_req_reg1 <= 0;
sync_req_dst <= 0;
end
else
begin
dst_req_reg <= sync_req;
dst_req_reg1 <= dst_req_reg;
sync_req_dst <= dst_req_reg1;
end
end
assign dst_pluse = ~sync_req_dst&&dst_req_reg1;
always@(posedge clk_dst or negedge rst_dst)begin
if(!rst_dst)
sync_ack <= 0;
else if(dst_req_reg1)
sync_ack <= 1;
else
sync_ack <= 0;
end
reg src_ack_reg,src_ack_reg1,sync_ack_req;
always@(posedge clk_req or negedge rst_req)begin
if(!rst_req)
begin
src_ack_reg <= 0;
src_ack_reg1 <= 0;
sync_ack_req <= 0;
end
else begin
src_ack_reg <= sync_ack;
src_ack_reg1 <= src_ack_reg;
sync_ack_req <= src_ack_reg1;
end
end
(2)脉冲宽度恒定的情况,可以直接将读时钟域同步后的脉冲反馈给写时钟域,这其实是depth=1的
异步FIFO。
module pluse_sync(
input clk_slow,//慢时钟域
input rst_slow,
input rst_fast,
input clk_fast,//快时钟域
output slow_pluse,
input fast_pluse
);
reg fast_level;
always@(posedge clk_slow or negedge rst_slow )begin
if(!rst_slow)
fast_level <= 0;
else if(fast_pluse)
fast_level <= 1;
else if(slow_to_fast[1])
fast_level <= 0;
end
reg pluse_fts;
always@(posedge clk_slow or negedge rst_slow)begin
if(!rst_slow)
pluse_fts <= 0;
else
pluse_fts <= fast_level;
end
reg [1:0]pluse_fts_reg;
always@(posedge clk_slow or negedge rst_slow)begin
if(!rst_slow)
pluse_fts_reg <= 0;
else
pluse_fts_reg <= {pluse_fts_reg[0],pluse_fts};
end
assign slow_pluse = ~pluse_fts_reg[1]&&pluse_fts_reg[0];
reg [1:0]slow_to_fast;
always@(posedge clk_fast or negedge rst_fast)begin
if(!rst_fast)
slow_to_fast <= 0;
else
slow_to_fast <= {slow_to_fast[0],pluse_fts_reg[1]};
end
2、电平同步器
如果在快时钟域的脉冲长度较长,可以采用电平同步器。
3、握手协议