XILINXのCoreGenで非同期FIFOを作って、異なるクロックドメイン間での信号の受け渡しをしようとしているのですが、どうしてもタイミングエラーが出てしまいます。
問題を単純化させるために、入力FDと、FIFOと出力FDのみを配置したデザインを作りました。
afifoというモジュールは、CoreGenで作った非同期FIFOです。BlockRAMを用いた独立クロックのFIFOを生成させています。
clkgenというのは、50.0MHzと50.2MHzのクロックを生成するモジュールです。
CoreGenで作ったFIFOといえども、このように微妙に異なる周波数のクロックを与えた場合、タイミングエラーが出てしまいます。
どんなネットでエラーが出ているのかと調べてみると・・
Slack (setup path): -1.016ns (requirement - (data path - clock path skew + uncertainty))
Source: inst_afifo/U0/xst_fifo_generator/gconvfifo.rf/grf.rf/gntv_or_sync_fifo.gcx.clkx/rd_pntr_gc_4 (FF)
Destination: inst_afifo/U0/xst_fifo_generator/gconvfifo.rf/grf.rf/gntv_or_sync_fifo.gcx.clkx/gsync_stage[1].wr_stg_inst/Q_reg_4 (FF)
Requirement: 0.081ns
Data Path Delay: 0.740ns (Levels of Logic = 1)(Component delays alone exceeds constraint)
Clock Path Skew: -0.169ns (2.490 - 2.659)
Source Clock: clk50_2mhz rising at 19.919ns
Destination Clock: clk50_0mhz rising at 20.000ns
Clock Uncertainty: 0.188ns
どうやらinst_afifo/U0/xst_fifo_generator/gconvfifo.rf/grf.rf/gntv_or_sync_fifo.gcx.clkx/rd_pntr_gc_4とかいう随分深い階層の中のネットがエラーを出しています。ただ、CoreGenの中の信号なので、ユーザとしては触ることができません。
注目すべきところは上のRequirement:0.081nsというところです。
今回のclkgenは、50MHzと50.2MHzを作っています。50.2MHzというのは50MHz×31.125÷31≒50.202MHzです。2つのクロックのタイミングは近づいたり離れたりしますが、もっとも近いところで0.081nsになるということです。
0.081nsで動くFFなんてありませんからタイミングエラーが出るのは仕方がないのですが、さて、どうしたものでしょう。
TIGというタイミング制約をかけてみます。TIGはタイミング制約を無視するという魔法のコマンドです。UCFファイルにTIGを書けばよいのですが、どうやらクロックに対してかけるものらしく、先にクロックのネットを指定しておきます。
今回のデザインでは、clk50_0mhzとclk50_2mhzという2つのクロックのネットがあるので、これらの2つのドメインを渡るところはタイミング解析をしないようにさせます。
NET "clk50_0mhz" TNM_NET = TMN_CLK_500;
NET "clk50_2mhz" TNM_NET = TMN_CLK_502;
TIMESPEC TS_CLK_500_TO_502 = FROM "TMN_CLK_500" TO "TMN_CLK_502" TIG;
TIMESPEC TS_CLK_502_TO_500 = FROM "TMN_CLK_502" TO "TMN_CLK_500" TIG;
すると、このように
タイミングエラーは消えました。
でも、これでよいのかどうかは疑問が残るところです。CoreGenの中で発生しているエラーは消えますが、本当に2つのクロック間で不注意に信号をつないでしまっているところがあったとしても発見できなくなります。
次に、7シリーズのBuildIn FIFOを使ってみます。CoreGenの2ページ目で一番下のチェックボックスを選ぶだけです。
結果に変化がありました。今まで2つのタイミングエラーがあったのが1つに減ったということです。
エラーの詳細を見てみると、
Slack (setup path): -3.296ns (requirement - (data path - clock path skew + uncertainty))
Source: inst_afifo/U0/xst_fifo_generator/gconvfifo.rf/gbiv5.bi/rstbt/wr_rst_reg (FF)
Destination: inst_afifo/U0/xst_fifo_generator/gconvfifo.rf/gbiv5.bi/v6_fifo.fblk/gextw[1].gnll_fifo.inst_extd/gonep.inst_prim/gf18e1_inst.sngfifo18e1 (RAM)
Requirement: 0.080ns
Data Path Delay: 3.057ns (Levels of Logic = 1)(Component delays alone exceeds constraint)
Clock Path Skew: -0.131ns (2.532 - 2.663)
Source Clock: clk50_0mhz rising at 4940.000ns
Destination Clock: clk50_2mhz rising at 4940.080ns
Clock Uncertainty: 0.188ns
なんと、どうやらリセット関係の信号で出ています。ユーザ回路からCoreGenに与えるリセットを削除してみたのですが、CoreGen内部でリセットを作っているらしく、エラーはなくなりませんでした。
結果をまとめると、
- CoreGenの非同期FIFOを使っていても、非常に近いタイミングで遷移する2つのクロックが与えられたときにはタイミングエラーが出る
- ビルトインFIFOにすれば少しはエラーが減るが、リセットまわりでどうしても出る。
結論としては、
- タイミングエラーを回避するには、2つのクロック間でTIGをかける
ということになります。これでよいのか!?
最近のコメント