verilog基本电路设计包括时钟域同步无缝切换异步fifo去抖滤波.docx
- 文档编号:4416109
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:11
- 大小:21.25KB
verilog基本电路设计包括时钟域同步无缝切换异步fifo去抖滤波.docx
《verilog基本电路设计包括时钟域同步无缝切换异步fifo去抖滤波.docx》由会员分享,可在线阅读,更多相关《verilog基本电路设计包括时钟域同步无缝切换异步fifo去抖滤波.docx(11页珍藏版)》请在冰豆网上搜索。
verilog基本电路设计包括时钟域同步无缝切换异步fifo去抖滤波
Verilog基本电路设计(包括:
时钟域同步、无缝切换、异步FIFO、去抖滤波))
Verilog基本电路设计
共包括四部分:
单bit跨时钟域同步时钟无缝切换异步FIFO去抖滤波
Verilog基本电路设计之一:
单bit跨时钟域同步(帖子:
bbs.eetop/thread-605419-1-1.html)看到坛子里不少朋友,对于基本数字电路存在这样那样的疑惑,本人决定开贴,介绍数字电路最常见的模块单元,希望给初学者带来帮助,也欢迎大佬们前来拍砖。
如果想要做数字设计,下面这些电路是一定会碰到的,也是所有大型IP,SOC设计必不可少的基础,主要包括异步信号的同步处理,同步FIFO,异步FIFO,时钟无缝切换,信号滤波debounce等等,后面会根据大家反馈情况再介绍新电路。
首先介绍异步信号的跨时钟域同步问题。
一般分为单bit的控制信号同步,以与多bit的数据信号同步。
多bit的信号同步会使用异步FIFO完成,而单bit的信号同步,又是时钟无缝切换电路以与异步FIFO电路的设计基础,这里先介绍单bit信号同步处理。
clka域下的信号signal_a,向异步的clkb域传递时,会产生亚稳态问题。
所有的亚稳态,归根结底就是setup/hold时间不满足导致。
在同一个时钟域下的信号,综合以与布线工具可以在data路径或者clock路径上插入buffer使得每一个DFF的setup/hold时间都满足;但是当signal_a在clkb域下使用时,由于clka与clkb异步,它们的相位关系不确定,那么在clkb的时钟沿到来时,无法确定signal_a此时是否处于稳定无变化状态,也即setup/hold时间无法确定,从而产生亚稳态。
这种异步信号在前后端流程里面是无法做时序分析的,也就是静态时序分析里常说的false_path。
消除亚稳态,就是采用多级DFF来采样来自另一个时钟域的信号,级数越多,同步过来的信号越稳定。
对于频率很高的设计,建议至少用三级DFF,而两级DFF同步则是所有异步信号处理的最基本要求。
单bit的信号跨时钟域同步,又分成电平信号同步以与脉冲信号同步。
电平信号,就是说clka下的信号signal_a在clkb看来,是一个很宽的信号,会保持多个clkb的时钟周期,一定能被clkb采到。
这种情况,只需要使用clkb用至少两级DFF连续抓signal_a即可,特别需要强调的是,此时signal_a必须是clka下的寄存器信号,如果signal_a是clka下的组合逻辑信号,一定要先在clka下用DFF抓一拍,再使用两级DFF向clkb传递。
这是因为clka下的组合逻辑信号会有毛刺,在clka下使用时会由setup/hold时间保证毛刺不会被clka采到,但由于异步相位不确定,组合逻辑的毛刺却极有可能被clkb采到。
电平信号的同步处理,一般用于知道确定的时钟频率大小关系或者极慢时钟下的信号向极快时钟域传递时使用,简单处理如下:
always(posedgeclkbornegedgerst_n)begin
if(!
rst_n)begin
levl_b_d1
levl_b_d2
levl_b_d3
end
elsebegin
levl_b_d1
levl_b_d2
levl_b_d3
endendassignpuls_b_pos=levl_b_d2&(~levl_b_d3);assignpuls_b_neg=levl_b_d3&(~levl_b_d2);
assignlevl_b_out=levl_b_d2;
上面三个输出分别是经过同步之后,clkb下可以使用的0变1脉冲信号,1变0脉冲信号以与电平信号。
再次强调:
levl_a_in必须是clka的DFF信号!
下面是更常见的,clka下的脉冲信号,同步到clkb时钟域下,它对于clka与clkb的时钟频率关系没有任何限制,快到慢,慢到快都没问题。
其主要原理就是先把脉冲信号在clka下展宽,变成电平信号,再向clkb传递,当确认clkb已经“看见”信号同步过去之后,再清掉clka下的电平信号。
脉冲信号同步处理电路,有两个地方使用了上面的电平信号同步处理原则,请仔细揣摩原因。
详细见下面的RTL,其中省略了信号定义声明:
modulesync_pulse(
//input
rst_n,//systemreset
clka,//clockA
clkb,//clockB
puls_a_in,//pulseinputfromclka
//output
puls_b_out,//pulseoutputinclkb
levl_b_out//leveloutputinclkb
);parameterDLY=1;//always(posedgeclkaornegedgerst_n)
begin
if(rst_n==1'b0)
signal_a
elseif(puls_a_in)
signal_a
elseif(signal_b1_a2)
signal_a
else;
endalways(posedgeclkbornegedgerst_n)
begin
if(rst_n==1'b0)
signal_b
else
signal_b
endalways(posedgeclkbornegedgerst_n)
begin
if(rst_n==1'b0)begin
signal_b_b1
signal_b_b2
end
elsebegin
signal_b_b1
signal_b_b2
end
endalways(posedgeclkaornegedgerst_n)
begin
if(rst_n==1'b0)begin
signal_b1_a1
signal_b1_a2
end
elsebegin
signal_b1_a1
signal_b1_a2
end
endassignpuls_b_out=signal_b_b1&(~signal_b_b2);
assignlevl_b_out=signal_b_b1;endmodule
下一篇讲时钟切换电路。
留下一个思考题:
clka下的同一个寄存器信号signal_a,电平宽度对clkb而言足够长,如果同时调用两个相同的电平同步模块向clkb时钟传递,分别得到levl_b1和levl_b2,那么在clkb时钟域下看到的lev_b1和levl_b2信号是否一样?
这个问题是实际设计中一不小心就会犯错的,如果能够想明白正确回答这个问题,异步信号的理解就可以过关了。
Verilog基本电路设计之二:
时钟无缝切换(帖子:
bbs.eetop/thread-605514-1-1.html)时钟切换分成两种方式,普通切换和去毛刺无缝切换。
普通切换,就是不关心切出的时钟是否存在毛刺,这种方式电路成本小。
如果时钟切换时,使用此时钟的模块电路处于非工作状态,或者模块电路被全局复位信号reset住的,即使切出毛刺也不会导致DFF误触发,这样的模块可以选择用此种切换方式。
写法很简单assignclk_o=sel_clkb?
clkb:
clka,当sel_clkb为1时选择clkb,否则选择clka。
不过在实际设计中,建议直接调用库里的MUX单元set_dont_touch,不要采用这里的assign写法,因为这种写法最后综合得到的可能不是MUX而是复杂组合逻辑,给前后端流程的时钟约束和分析带来不便。
无缝切换,就是切换时无毛刺时钟平稳过渡。
在时钟切换中,只要出现比clka或者clkb频率更高的窄脉冲,不论是窄的高电平还是窄的低电平,都叫时钟毛刺。
工作在切换后时钟clk_o下的电路模块,综合约束是在max{clka,clkb}频率下的,也就是说设计最后signoff的时候,只保证电路可以稳定工作的最高频率是max{clka,clkb},如果切换中出现更高频的时钟毛刺,电路可能出现无法预知的结果而出错。
无缝切换,一般用在处于工作状态的模块需要调频或者切换时钟源,比如部系统总线,CPU等。
你刚用手机打完游戏后马上关屏听音乐,这两种场景中,CPU在满足性能前提下为了控制功耗,其工作频率会动态地从很高调至较低,此时就可能是在CPU一直处于工作状态下,通过无缝切换时钟源头实现的。
在无缝切换电路中,切换信号sel_clkb可以是任意时钟域下的信号,包括但不限于clka或者clkb域,但是sel_clkb必须是一个DFF输出信号;clka与clkb的频率大小相位关系可以任意。
无缝切换需要解决两个问题,一是异步切换信号的跨时钟域同步问题,这里需要使用《Verilog基本电路设计之一》里的同步电路原理消除亚稳态;二是同步好了的切换信号与时钟信号如何做逻辑,才能实现无毛刺。
下面写出无缝切换电路的主体部分,忽略了部信号的定义声明等。
moduleclk_switch(
rst_n,
clka,
clkb,
sel_clkb,
clk_o
);
always(posedgeclkaornegedgerst_n)
begin
if(!
rst_n)begin
sel_clka_d0
sel_clka_d1
end
elsebegin
sel_clka_d0
sel_clka_d1
end
end//part2
//always(posedgeclka_nornegedgerst_n)
always(posedgeclkaornegedgerst_n)
begin
if(!
rst_n)begin
sel_clka_dly1
sel_clka_dly2
sel_clka_dly3
end
elsebegin
sel_clka_dly1
sel_clka_dly2
sel_clka_dly3
end
end//part3
//always(posedgeclkb_nornegedgerst_n)
always(posedgeclkbornegedgerst_n)
begin
if(!
rst_n)begin
sel_clkb_d0
sel_clkb_d1
end
elsebegin
sel_clkb_d0
sel_clkb_d1
end
end//part4
//always(posedgeclkb_nornegedgerst_n)
always(posedgeclkbornegedgerst_n)
begin
if(!
rst_n)begin
sel_clkb_dly1
sel_clkb_dly2
sel_clkb_dly3
end
elsebegin
sel_clkb_dly1
sel_clkb_dly2
sel_clkb_dly3
end
end//part5
clk_gate_##xclk_gate_a(.CP(clka),.EN(sel_clka_dly3),.Q(clka_g).TE(1'b0));
clk_gate_##xclk_gate_b(.CP(clkb),.EN(sel_clkb_dly3),.Q(clkb_g).TE(1'b0));
//assignclka_g=clka&sel_clka_dly3;
//assignclkb_g=clkb&sel_clkb_dly3;
assignclk_o=clka_g|clkb_g;
endmodule
上面是我认为比较合理的无缝切换电路,其他切换方式跟这个会有些许出入,但基本小异原理是一样的。
有几点说明:
1、抛开注释掉的电路不看,由于part5部分直接调用库里的clockgatingcell,使得整个切换电路全部只需要用到时钟上升沿,无需额外定义反向时钟,精简了DC综合的时钟约束;直接调用gatingcell的另一个好处是,前后端工具会自动检查gatingcell的CP信号与EN信号的setup/hold时间,使得gating后的Q时钟输出无毛刺尖峰。
TE端可以根据实际需要接上scan测试模式信号。
如果使用part5部分的gatingcell实现,前面的part1,2,3,4全部替换成注释掉的反相时钟也是没有问题。
2、part2和part4部分,具体需要多少级DFF,甚至完全不要也是可以的,这就回到了《Verilog基本电路设计之一》里讨论的到底多少级DFF消除亚稳态才算合理的问题。
时钟频率很低可能无所谓,如果时钟频率达到GHz,这部分建议至少保留三级DFF,因为三级DFF延时也仅仅只有3ns的时间裕度。
没必要为了省这么几个DFF降低电路可靠性,在复杂IP以与大型SOC系统中,你会发现多几十个DFF,面积上可以忽略,系统可靠性和稳定性才是首要的。
3、如果part5部分希望使用注释掉的两行“与”逻辑实现时钟gating,此时part1与part3使用正相或者反相时钟都可以,但是必须把part2和part4部分改为注释掉的反相时钟实现,目的是初步从RTL设计上避免“与”逻辑的毛刺,同时还需要后端配合,因为很多后端工具对时钟“与”逻辑的clockgatingcheck未必会检查。
用clk下降沿拍出的en信号,再跟clk做与逻辑得到的门控时钟,在RTL仿真阶段看到的一定不会有毛刺,但是布线完成后,如果clk相对en后移,那与逻辑得到的门控时钟就有毛刺了。
这就是用与逻辑做门控的缺点,由于后端工具可能不会去检查这个与门的时序关系而导致出错。
但直接调用库里的gatingcell,工具天然就会去检查这个时序,免去人工确认的后顾之忧。
最后,请大家仔细看看sel_clka_d0(~sel_clkb_dly3)和sel_clkb_d0
Verilog基本电路设计之三:
异步FIFO(帖子:
bbs.eetop/thread-605632-1-1.html)FIFO用于为匹配读写速度而设置的数据缓冲buffer,当读写时钟异步时,就是异步FIFO。
多bit的数据信号,并不是直接从写时钟域同步到读时钟域的,而是读写时钟域分别派遣了一个信使,去通知对方时钟域,当前本方所处的读写情况,来判断还能不能写以与可不可以读,这两个信使就是读写指针。
在《Verilog基本电路设计之一》里已讨论过,即使单bit的异步信号,通过两个相同的同步电路,达到clkb域时都可能“长”的不是一个模样,更加不用说多bit的异步信号同时传递到clkb域会变成什么五花八门的模样了。
这里读写指针不是单bit信号,它们如何向对方时钟域去同步呢?
格雷码!
它的特点是每次只有一个bit发生变化,这样就把多bit信号同步转变为了单bit信号同步,这也是为什么多bit的格雷码信号,可以类似于单bit信号那样,直接使用两级DFF去同步的根本原因。
下面给出异步FIFO的主体部分,同样,省略了信号声明定义。
moduleasyn_fifo(
//input
af_wclk,//async-FIFOclearinwriteclock
af_rclk,//async-FIFOclearinreadclock
rst_n,//systemreset
af_wr_en,//async-FIFOwriteenable
af_rd_en,//async-FIFOreadenable
af_dati,//async-FIFOdatain
//output
af_full,//Async-FIFOfullflag
af_empty,//Async-FIFOemptyflag
af_dato//Async-FIFOdataout
);//-------------------------datainput--------------------------
assignnxt_wptr_wclk=(af_wr_en&&!
af_full)?
(wptr_wclk+1'b1):
wptr_wclk;
assignnxt_wptr_gray=(nxt_wptr_wclk>>1)^nxt_wptr_wclk;always(posedgeaf_wclkornegedgerst_n)
begin
if(rst_n==1'b0)begin
wptr_wclk
wptr_gray
end
elsebegin
wptr_wclk
wptr_gray
end
endreg[31:
0]ram[15:
0];//
always(posedgeaf_wclk)
begin
if(af_wr_en==1'b1)
ram[wptr_wclk[3:
0]]
else;
end//------------------------dataoutput---------------------------
assignnxt_rptr_rclk=(af_rd_en&&!
af_empty)?
(rptr_rclk+1'b1):
rptr_rclk;
assignnxt_rptr_gray=(nxt_rptr_rclk>>1)^nxt_rptr_rclk;always(posedgeaf_rclkornegedgerst_n)
begin
if(rst_n==1'b0)begin
rptr_rclk
rptr_gray
end
elsebegin
rptr_rclk
rptr_gray
end
endassignaf_dato=ram[rptr_rclk[3:
0]];//syncreadpointer
always(posedgeaf_wclkornegedgerst_n)
begin
if(rst_n==1'b0)begin
rptr_sp1
rptr_sp2
end
elsebegin
rptr_sp1
rptr_sp2
end
end//syncwritepointer
always(posedgeaf_rclkornegedgerst_n)
begin
if(rst_n==1'b0)begin
wptr_sp1
wptr_sp2
end
elsebegin
wptr_sp1
wptr_sp2
end
endassignaf_full=(wptr_gray=={~rptr_sp2[4],~rptr_sp2[3],rptr_sp2[2:
0]});
assignaf_empty=(rptr_gray==wptr_sp2);assignwptr_bin[4]=wptr_sp2[4];
assignwptr_bin[3]=(^wptr_sp2[4:
3]);
assignwptr_bin[2]=(^wptr_sp2[4:
2]);
assignwptr_bin[1]=(^wptr_sp2[4:
1]);
assignwptr_bin[0]=(^wptr_sp2[4:
0]);assignrptr_bin[4]=rptr_sp2[4];
assignrptr_bin[3]=(^rptr_sp2[4:
3]);
assignrptr_bin[2]=(^rptr_sp2[4:
2]);
assignrptr_bin[1]=(^rptr_sp2[4:
1]);
assignrptr_bin[0]=(^rptr_sp2[4:
0]);assignaf_wlevel=wptr_wclk-rptr_bin;
assignaf_rlevel=wptr_bin-rptr_rclk;
assignaf_half_full=(af_rlevel>=5'h7);endmodule
上面给出的是深度16,宽度32的示例,大家可以使用parameter参数化定义深度和宽度,方便不同需求下的调用。
除了空满信号标志,也可以根据需要做出半空半满之类信号。
上面需要注意的一点就是,格雷码必须在本时钟域下DFF输出,再往另一个时钟域同步。
同步FIFO呢,就不用有格雷码转换,设计更加简单,就不专门开贴描述了。
Verilog基本电路设计之四:
去抖滤波(帖子:
bbs.eetop/thread-605729-1-1.html)debounce电路,就是常说的去抖滤波,主要用在芯片的PAD输入信号,或者模拟电路输出给数字电路的信号上。
parameterBIT_NUM=4;
reg[BIT_NUM-1:
0]signal_deb;//
always(posedgeclkornegedgerst_n)
begin
if(rst_n==1'b0)
signal_deb
else
signal_deb
endalways(posedgeclkornegedgerst_n)
begin
if(rst_n==1'b0)
signal_o
elseif(signal_deb[3:
1]==3'b111)
signal_o
elseif(signal_deb[3:
1]==3'b000)
signal_o
else;
end
上面的电路,第一个always,还兼顾了去亚稳态作用。
它可以滤掉的宽度是两个clk的cycle,对于大于两个cycle而小于三个cycle的信号,有些可以滤掉,有些不能滤掉,这与signal_i相对clk的相位有关。
根据希望滤除的宽度相关,换算到clk下是多少个cycle数,从而决定使用多少级DFF。
如果希望滤除的宽度相对cycle数而言较大,可以先在clk下做一个计数器,产生固定间隔的脉冲,再在脉冲信号有效时使用多级DFF去抓signal_i;或者直接将clk分频后再使用。
完毕
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- verilog 基本 电路设计 包括 时钟 同步 无缝 切换 异步 fifo 滤波