1、电平信号的同步处理,一般用于知道确定的时钟频率大小关系或者极慢时钟下的信号向极快时钟域传递时使用,简单处理如下:always (posedge clkb or negedge rst_n)begin if (!rst_n) begin levl_b_d1 levl_b_d2 levl_b_d3 end else begin endendassign puls_b_pos = levl_b_d2 & (levl_b_d3);assign puls_b_neg = levl_b_d3 & (levl_b_d2);assign levl_b_out = levl_b_d2;上面三个输出分别是经过同步
2、之后,clkb下可以使用的0变1脉冲信号,1变0脉冲信号以与电平信号。再次强调:levl_a_in必须是clka的DFF信号!下面是更常见的,clka下的脉冲信号,同步到clkb时钟域下,它对于clka与clkb的时钟频率关系没有任何限制,快到慢,慢到快都没问题。其主要原理就是先把脉冲信号在clka下展宽,变成电平信号,再向clkb传递,当确认clkb已经“看见”信号同步过去之后,再清掉clka下的电平信号。脉冲信号同步处理电路,有两个地方使用了上面的电平信号同步处理原则,请仔细揣摩原因。详细见下面的RTL,其中省略了信号定义声明:module sync_pulse ( / input rst
3、_n, / system reset clka, / clockA clkb, / clockB puls_a_in, / pulse input from clka / output puls_b_out, / pulse output in clkb levl_b_out / level output in clkb );parameter DLY = 1; /always (posedge clka or negedge rst_n)begin if (rst_n = 1b0) signal_a else if (puls_a_in) else if (signal_b1_a2) els
4、e ;endalways (posedge clkb or negedge rst_n) signal_b elseb0) begin signal_b_b1 signal_b_b2 endalways (posedge clka or negedge rst_n) signal_b1_a1 signal_b1_a2 endassign puls_b_out = signal_b_b1 & (signal_b_b2) ;assign levl_b_out = signal_b_b1 ;endmodule下一篇讲时钟切换电路。留下一个思考题:clka下的同一个寄存器信号signal_a,电平宽度
5、对clkb而言足够长,如果同时调用两个相同的电平同步模块向clkb时钟传递,分别得到levl_b1和levl_b2,那么在clkb时钟域下看到的lev_b1和levl_b2信号是否一样?这个问题是实际设计中一不小心就会犯错的,如果能够想明白正确回答这个问题,异步信号的理解就可以过关了。 Verilog基本电路设计之二: 时钟无缝切换(帖子:bbs.eetop/thread-605514-1-1.html)时钟切换分成两种方式,普通切换和去毛刺无缝切换。普通切换,就是不关心切出的时钟是否存在毛刺,这种方式电路成本小。如果时钟切换时,使用此时钟的模块电路处于非工作状态,或者模块电路被全局复位信号r
6、eset住的,即使切出毛刺也不会导致DFF误触发,这样的模块可以选择用此种切换方式。写法很简单 assign clk_o = sel_clkb ? clkb : clka ,当sel_clkb为1时选择clkb,否则选择clka。不过在实际设计中,建议直接调用库里的MUX单元set_dont_touch,不要采用这里的assign写法,因为这种写法最后综合得到的可能不是MUX而是复杂组合逻辑,给前后端流程的时钟约束和分析带来不便。无缝切换,就是切换时无毛刺时钟平稳过渡。在时钟切换中,只要出现比clka或者clkb频率更高的窄脉冲,不论是窄的高电平还是窄的低电平,都叫时钟毛刺。工作在切换后时钟c
7、lk_o下的电路模块,综合约束是在maxclka,clkb频率下的,也就是说设计最后signoff的时候,只保证电路可以稳定工作的最高频率是maxclka,clkb,如果切换中出现更高频的时钟毛刺,电路可能出现无法预知的结果而出错。无缝切换,一般用在处于工作状态的模块需要调频或者切换时钟源,比如部系统总线,CPU等。你刚用手机打完游戏后马上关屏听音乐,这两种场景中,CPU在满足性能前提下为了控制功耗,其工作频率会动态地从很高调至较低,此时就可能是在CPU一直处于工作状态下,通过无缝切换时钟源头实现的。在无缝切换电路中,切换信号sel_clkb可以是任意时钟域下的信号,包括但不限于clka或者c
8、lkb域,但是sel_clkb必须是一个DFF输出信号;clka与clkb的频率大小相位关系可以任意。无缝切换需要解决两个问题,一是异步切换信号的跨时钟域同步问题,这里需要使用Verilog基本电路设计之一里的同步电路原理消除亚稳态;二是同步好了的切换信号与时钟信号如何做逻辑,才能实现无毛刺。下面写出无缝切换电路的主体部分,忽略了部信号的定义声明等。module clk_switch ( rst_n, clka, clkb, sel_clkb, clk_oalways (posedge clka or negedge rst_n) sel_clka_d0 sel_clka_d1 end/ pa
9、rt2/always (posedge clka_n or negedge rst_n) sel_clka_dly1 sel_clka_dly2 sel_clka_dly3 end/ part3/always (posedge clkb_n or negedge rst_n)always (posedge clkb or negedge rst_n) sel_clkb_d0 sel_clkb_d1 sel_clkb_d0 end/ part4 sel_clkb_dly1 sel_clkb_dly2 sel_clkb_dly3 end/ part5clk_gate_#x clk_gate_a (
10、 .CP(clka), .EN(sel_clka_dly3), .Q(clka_g) .TE(1b0) );clk_gate_#x clk_gate_b ( .CP(clkb), .EN(sel_clkb_dly3), .Q(clkb_g) .TE(1/assign clka_g = clka & sel_clka_dly3 ;/assign clkb_g = clkb & sel_clkb_dly3 ;assign clk_o = clka_g | clkb_g ;上面是我认为比较合理的无缝切换电路,其他切换方式跟这个会有些许出入,但基本小异原理是一样的。有几点说明:1、抛开注释掉的电路不看
11、,由于part5部分直接调用库里的clock gating cell,使得整个切换电路全部只需要用到时钟上升沿,无需额外定义反向时钟,精简了DC综合的时钟约束;直接调用gating cell的 另一个好处是,前后端工具会自动检查gating cell的CP信号与EN信号的setup/hold时间,使得gating后的Q时钟输出无毛刺尖峰。TE端可以根据实际需要接上scan测试模式信号。如果使用part5部分的gating cell实现,前面的part1,2,3,4全部替换成注释掉的反相时钟也是没有问题。2、part2和part4部分,具体需要多少级DFF,甚至完全不要也是可以的,这就回到了Ve
12、rilog基本电路设计之一里讨论的到底多少级DFF消除亚稳态才算合理的问题。时钟频率很低可能无所谓,如果时钟频率达到GHz,这部分建议至少保留三级DFF,因为三级DFF延时也仅仅只有3ns的时间裕度。没必要为了省这么几个DFF降低电路可靠性,在复杂IP以与大型SOC系统中,你会发现多几十个DFF,面积上可以忽略,系统可靠性和稳定性才是首要的。3、如果part5部分希望使用注释掉的两行“与”逻辑实现时钟gating,此时part1与part3使用正相或者反相时钟都可以,但是必须把part2和part4部分改为注释掉的反相时钟实现,目的是初步从RTL设计上避免“与”逻辑的毛刺,同时还需要后端配合,
13、因为很多后端工具对时钟“与”逻辑的clock gating check未必会检查。用clk下降沿拍出的en信号,再跟clk做与逻辑得到的门控时钟,在RTL仿真阶段看到的一定不会有毛刺,但是布线完成后,如果clk相对en后移,那与逻辑得到的门控时钟就有毛刺了。这就是用与逻辑做门控的缺点,由于后端工具可能不会去检查这个与门的时序关系而导致出错。但直接调用库里的gating cell,工具天然就会去检查这个时序,免去人工确认的后顾之忧。最后,请大家仔细看看sel_clka_d0 (sel_clkb_dly3) 和sel_clkb_d0 Verilog基本电路设计之三: 异步FIFO(帖子:bbs.e
14、etop/thread-605632-1-1.html)FIFO用于为匹配读写速度而设置的数据缓冲buffer,当读写时钟异步时,就是异步FIFO。多bit的数据信号,并不是直接从写时钟域同步到读时钟域的,而是读写时钟域分别派遣了一个信使,去通知对方时钟域,当前本方所处的读写情况,来判断还能不能写以与可不可以读,这两个信使就是读写指针。在Verilog基本电路设计之一里已讨论过,即使单bit的异步信号,通过两个相同的同步电路,达到clkb域时都可能“长”的不是一个模样,更加不用说多bit的异步信号同时传递到clkb域会变成什么五花八门的模样了。这里读写指针不是单bit信号,它们如何向对方时钟域
15、去同步呢?格雷码!它的特点是每次只有一个bit发生变化,这样就把多bit信号同步转变为了单bit信号同步,这也是为什么多bit的格雷码信号,可以类似于单bit信号那样,直接使用两级DFF去同步的根本原因。下面给出异步FIFO的主体部分,同样,省略了信号声明定义。module asyn_fifo ( af_wclk , / async-FIFO clear in write clock af_rclk , / async-FIFO clear in read clock af_wr_en, / async-FIFO write enable af_rd_en, / async-FIFO read
16、 enable af_dati, / async-FIFO data in /output af_full , / Async-FIFO full flag af_empty, / Async-FIFO empty flag af_dato / Async-FIFO data out/- data input -assign nxt_wptr_wclk = (af_wr_en & !af_full) ? (wptr_wclk + 1b1) : wptr_wclk ;assign nxt_wptr_gray = (nxt_wptr_wclk 1) nxt_wptr_wclk ;always (p
17、osedge af_wclk or negedge rst_n) wptr_wclk wptr_gray endreg 31:0 ram15:0 ; /always (posedge af_wclk) if (af_wr_en = 1b1) ramwptr_wclk3:0 end/- data output -assign nxt_rptr_rclk = (af_rd_en &af_empty) ? (rptr_rclk + 1 rptr_rclk ;assign nxt_rptr_gray = (nxt_rptr_rclk 1) nxt_rptr_rclk ;always (posedge
18、af_rclk or negedge rst_n) rptr_rclk rptr_gray endassign af_dato = ramrptr_rclk3:0 ;/ sync read pointer rptr_sp1 rptr_sp2 end/ sync write pointer wptr_sp1 wptr_sp2 endassign af_full = (wptr_gray = rptr_sp24,rptr_sp23,rptr_sp22:0) ;assign af_empty = (rptr_gray = wptr_sp2) ;assign wptr_bin4 = wptr_sp24
19、 ;assign wptr_bin3 = (wptr_sp24:3) ;assign wptr_bin2 = (wptr_sp24:2) ;assign wptr_bin1 = (wptr_sp24:1) ;assign wptr_bin0 = (wptr_sp24:0) ;assign rptr_bin4 = rptr_sp24 ;assign rptr_bin3 = (rptr_sp24:assign rptr_bin2 = (rptr_sp24:assign rptr_bin1 = (rptr_sp24:assign rptr_bin0 = (rptr_sp24:assign af_wl
20、evel = wptr_wclk - rptr_bin ;assign af_rlevel = wptr_bin - rptr_rclk ;assign af_half_full = (af_rlevel = 5h7) ;上面给出的是深度16,宽度32的示例,大家可以使用parameter参数化定义深度和宽度,方便不同需求下的调用。除了空满信号标志,也可以根据需要做出半空半满之类信号。上面需要注意的一点就是,格雷码必须在本时钟域下DFF输出,再往另一个时钟域同步。同步FIFO呢,就不用有格雷码转换,设计更加简单,就不专门开贴描述了。Verilog基本电路设计之四: 去抖滤波(帖子:bbs.ee
21、top/thread-605729-1-1.html)debounce电路,就是常说的去抖滤波,主要用在芯片的PAD输入信号,或者模拟电路输出给数字电路的信号上。parameter BIT_NUM = 4 ;reg BIT_NUM-1 : 0 signal_deb ;always (posedge clk or negedge rst_n)b0) signal_deb else endalways (posedge clk or negedge rst_n) signal_o else if (signal_deb3:1=3b111)b000)end上面的电路,第一个always,还兼顾了去亚稳态作用。它可以滤掉的宽度是两个clk的cycle,对于大于两个cycle而小于三个cycle的信号,有些可以滤掉,有些不能滤掉,这与signal_i相对clk的相位有关。根据希望滤除的宽度相关,换算到clk下是多少个cycle数,从而决定使用多少级DFF。如果希望滤除的宽度相对cycle数而言较大,可以先在clk下做一个计数器,产生固定间隔的脉冲,再在脉冲信号有效时使用多级DFF去抓signal_i;或者直接将clk分频后再使用。 完毕
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1