開発日記2020年11月
HDMI 2入力、1出力回路
2020.11.24
Kintex-7で、DDR3メモリを介したHDMI 2入力、HDMI 1出力+USB3.0な回路が出来ました。
やりたいことは下の図のようなシンプルなことなのですが、
Vivado Block Designはぐっちゃーという感じになりました。
そもそも真ん中にあるFX3というブロックに大量の信号が出入りしているのが悪いのですが、これは、EZ-USB FX3をカプセル化したブロックで、USB 3.0で高速転送できるだけでなく、HDMIデコーダのステータスなどを読みだせるようにしています。
各種ステータスやコントロール信号が多いからこんなにぐちゃぐちゃしているのですね。綺麗にするにはInterfaceを定義するしかありません。
昨日作ったフィルタにはHとVのカウントを数える機能があるので、その数えたカウント数をUSBで読み出すと、画面の解像度もわかります。
ここまでは完璧に動いたので、HDMIの2個目の出力を作ることにしましょう。
HDMIの安定入力のために「フィルタ」を追加
2020.11.23
HDMIの出力が安定してできるようになったので、今度はHDMIの入力を安定にしたいと考えました。
今の安定性の問題は、画面の上方に4ラインくらいのごみラインが出て、画面が上下に揺れることです。
dvi2rgbでHDMIの信号をデコードし、その中にある垂直同期信号的な信号(vsync)や、水平同期信号的な信号(hsync)、それとvdeを取り出して、内蔵ロジアナで見てみることにしました。
まず、VSYNCが来る際の挙動です。
HSYNCとVSYNCが同時に立ち上がっていますね。HSYNCの立ち上がりの次でhcount=0にクリアして、HSYNCの長さを測ってみたら44クロックでした。
どうやら、HDMIではHSYNCやVSYNCは8b/10b変換して、c0,c1,c2,c3という符号として送られてきています。これらの符号がいつ送られてくるかはソース機器によるのかもしれません。(余談ですが、HDMIの8b/10bはPCI ExpressやSATAの8b/10bとは違うコード体系なんじゃないかなと思います)
このようにして、水平のカウント数や垂直のライン数を数えて、VDEがHになる期間を調べました。
HやVの数を図にしてみます。
HDMIの1920×1080pでは、ブランキング期間を含めると2200×1125のタイミングで送られてきていました。2200×1125×60fps = 148.5MHzなので計算も合います。
さて、入力が安定しない機器では、VSYNCが来てから2回目のHSYNCが立ち上がるVCOUNT=1のときにvdeがバタバタ動いているのがわかります。
VCOUNT=2のときにも、vdeはバタバタ動いています。
HDMIの機器によっては上記のVDEがライン1~4くらいの間にバタバタしながらやってくるので、AXI Video DMAなどのカウンタが誤動作してしまいます。それがノイズや信号の減衰によるものなのか、規格的にそうなのかはわかりません。たぶん、FPGAに到達したときのTMDS波形の質が悪いからなんじゃないかなと思います。
そこで、VCOUNTが31以下ならVDEがHになっても強制的にLにするというチート的な回路を入れてみたところ、画面の揺れはぴたりと収まりました。
process(pixclk) begin
if(pixclk'event and pixclk='1') then
hsync_o <= hsync_i;
vsync_o <= vsync_i;
data_o <= data_i;
if(disable_filter_i = '1') then
vde_filter <= vde_i;
else
if(vcount >= 32) and (vcount < 1121) then
vde_filter <= vde_i;
else
vde_filter <= '0';
end if;
end if;
vde_filter_d <= vde_filter;
end if;
end process;
こんなんでいいのかという疑問はありますが、画像が劇的に安定したのでした。
AXI Video DMAで画面を切り替える
2020.11.22
XILINXのIPコアでAXI Video DMAというのがあります。これは、DDR3 SDRAMから自動的にデータを取ってきてAXI Streamから出力するということをしてくれます。
使い方は結構複雑です。
- AXI VDMAには、AXI Liteでレジスタ設定をする必要があるため、AXI Liteを出力できるIPが必要
- AXI VDMAの出力は32bitなので、RGB 24bit化するためにAXI Subset Converterを使う
- AXI StreamをAXI Video Outに入れる
- AXI Video Outのタイミング信号生成用に別途Video Timing Controller(v_tc)を使う
- AXI Video Outの出力はRGBなので、TMDSコンバータを別途入れる
これで、DDR3 SDRAMの特定のアドレスから繰り返しデータを読み出して画像表示してくれます。ここまでは他社の評価ボードでもやっているので難しくはありません。
しかし、画面を切り替えたい場合はどうすればいいのでしょう。
次のようにしたらうまくいきました。
① AXI Video DMAの設定で、Frame Buffersを2以上にする
② MM2S_DMACRレジスタ(アドレス0)のbit1 (Circular_Park)を'0'にする。
③ MM2S_START_ADDRESS1、MM2S_START_ADDRESS2、MM2S_START_ADDRESS3・・・に出力したいメモリのアドレスを書いておく。
④ 表示を切り替えたいときに、PARK_PTR_REGレジスタ(アドレス28h)のRdFrmPtrRefを書き換える。
このRdFrmPtrRefに、フレームバッファのポインタを書き込むことでDMA先頭アドレスが変わるという仕組みのようです
画面の切り替えは直接アドレスを指定するのではなく、フレームバッファの番号で設定するようでした。私のやり方が悪いのかもしれませんが、動作中にMM2S_START_ADDRESSxレジスタを書き換えてみても表示は切り替わりませんでした。昔のPCのように表示アドレスの先頭を書き換えるということでの画面スクロールはできなさそうです。ちょっと残念でした。
ついに、Kintex-7で安定したHDMI 1080p出力に成功!
2020.11.21
ついにKintex-7での安定したHDMIの1080p出力に成功しました。USB3.0で書き込んだ画像をHDMIで表示しています。
「安定した」というのは、Vivadoのバージョンによらず、他の回路に影響されず、XDCファイルにCLOCK_DEDICATED_ROUTEを指定することもなく、Warningも出さずに論理合成できるようになったことを意味します。7シリーズクロックリソースの理解が鍵でした。
リソースの使用量はこんなもん。
使っているボードは、HDMIを4ポート備えたKintex-7ボード「Cosmo-K」です。
ただ、最初、HDMI出力をしてみると、液晶モニターによっては画面が出たり出なかったりしました。
家庭用テレビでは映るのにメインで使っている液晶モニタには画像が出ない。(# ゚Д゚)
モニターによって映ったり映らなかったりする原因は、HDMIコネクタの18番端子「+5V」にありました。
Cosmo-Kの回路図では+5Vの端子と、システムの+5Vの間にはNI(未実装の抵抗のパッドのみ)となっていて、HDMIの+5V端子はオープンになっていました。
ここに1kΩの抵抗をつないだら、最後まで映らなかったモニターでも画像が出るようになりました。
原因を見つけたきっかけは、Zynqberryの回路図です。
この回路は非常に参考になります。5Vは、ソースの5V→シンクへ供給するということが明確に示されているからです。
他にも、DigilentのPYNQやZYBOの回路図も調べたのですが、システムの5Vと直接つながっているだけなので、どちらからどちらへ供給するものかわからなかった
+5Vってモニターからシンク機器へ電力を供給するものだと思っていましたが、ソースからシンクへ電流を供給するものだったのです。しかも流せる電流が55mAと微弱なものだそうです。[参考記事] たぶんEDID(モニタの解像度などの情報を得るROM)の電源ですね。
どうやら私がメインで使っている液晶モニタは、この5Vが来ているかどうかでソース機器の接続を判断していたようです。
あと、HDMIのMISC的な端子について。
- CECはオープンでよいです。オープンが嫌な場合は3.3Vにプルアップします。
- SDA、SDLは3.3Vにプルアップしておきます。操作する必要はありません。
- HPDは、100kΩとか200kΩとかでプルダウンします。シンク機器が接続されるとL→Hに上がるので、何かしたければします。
これらは回路上でプルアップやプルダウンをしておけばよく、必ずしもFPGAに接続して操作する必要はない信号なのです。
あと、XILINXのVideoコアにおけるAXI Stream上のRGBの配列は「RBG」になっているようです。なんでこんな変則的なんでしょうね。
AXI Liteのコアを作り直したらビデオ出力が動いた!
2020.11.20
もうね、激おこぷんぷん丸ですよ。
Video Out回路が動かない原因が、Vivadoが生成したステートマシンのフライングだったなんて・・。ツールが自動で生成したIPならちゃんと動くと思うでしょ!?
ここでグダグダいっても仕方がないので、正しいステートマシンの作り方を解説します。
ステートマシンってのは、中に「カウンタ」を入れるんです。ベースとなるカウンタを作って、そのカウンタがカウントアップする条件をAWREADYやBVALIDなどいろいろな信号に関連付けていくのです。
こういうとき、考え方を整理するため、AXI Liteの基本的な動かし方を図にしてみます。
冗長なステートもありますが、気にせずにいきましょう。
とりあえず、0~6まで数えられるカウンタを用意して、そのカウンタの値=ステートとします。カウンタの遷移はcase文で作ります。
WVALIDやAWVALIDなどの信号出力は、特定のステートでそれを出す(ステートマシン中に遷移する信号として記述する)か、ステートをデコードして出す(ステートマシンの外側で書く)ようにします。
これを実際のコードに落とし込みます。上のステートマシンをそのまま書くとあまりにも冗長なので少し縮めています
process(clk) begin
if(clk'event and clk='1') then
if(aresetn = '0') then
wstate <= 0;
windex <= 0;
awvalid <= '0';
wvalid <= '0';
bready <= '0';
else
case wstate is
when 0 =>
awvalid <= '0';
wvalid <= '0';
if(windex < 16) then
wstate <= wstate + 1;
end if;
when 1 =>
case windex is
when 0 =>
awaddr <= x"00000000";--MM2S_DMACR
wdata <= x"00000003";--MM2S_DMACR
when 1 =>
awaddr <= x"0000005c";--MM2S_START_ADDRESS1
wdata <= FRAME_ADDRESS_0;--x"00000000;--MM2S_START_ADDRESS1
when 2 =>
awaddr <= x"00000060";--MM2S_START_ADDRESS2
wdata <= FRAME_ADDRESS_1;--MM2S_START_ADDRESS2
・・・(中略)・・・
when others =>
awaddr <= x"0000FFFF";
wdata <= x"00000000";
end case;
awvalid <= '1';
wstate <= wstate + 1;
when 2 =>
if(awready = '1') then
awvalid <= '0';
wvalid <= '1';
wstate <= wstate + 1;
end if;
when 3 =>
if(wready = '1') then
wstate <= wstate + 1;
bready <= '1';
wvalid <= '0';
end if;
when 4 =>
if(bvalid = '1') then
wstate <= wstate + 1;
end if;
when 5 =>
windex <= windex + 1;
wstate <= 0;
when others =>
wstate <= 0;
end case;
end if;
end if;
end process;
シンプルでしょ?ちゃんと動きます。
Vivadoが生成した回路と違って、アドレス系のハンドシェイクとデータ系のハンドシェイクの順序ができているし、BVALIDをちゃんと待つようにもなっている。
あと、VHDLやVerilogでは、if文やcase文の中ではstate_next <= *** みたいな信号を作るだけにしておいて、別のprocess文でstate <= state_nextとする書き方もありますが、分かりにくくなるのでやめましょう。
「case文でstateを判断し、遷移条件を書いて次のstateを直接指定する」ようにしてください。2つに分けない。
波形を見ると、当たり前ですがハンドシェイクが効いています。AWVALID & AWREADYが来てからWVALIDを出し、WVALID & WREADYが来てBVALIDを待ってから次のデータを出すようになっています。
AXI LiteでAXI Video DMAコアを設定したら、AXI MMが動き、AXI Streamが動くとう連携した動作も見えるようになりました。(ILAだと3つのILAコアが別々だから、こういうデバッグはやりにくいですよね。)
Video DMAが動き出し、Streamが動き出し、無事にv_tcとaxis_vid_outもロックがかかるようになりました。
これでHDMI端子からメモリの中身の画像が出力されるようになりました。
AXIバスを横から覗き見るVivadoのIPを作る
2020.11.19
昨日、ビデオまわりのAXIのバスの動きを調べてみようとILAを入れようとしていろいろハマりました。エラー解決はできたのですが、VivadoからPlatform Cable USBにつなごうとするとhw_serverがすでに立ち上がってるとか、見つからないとか、とにかく接続性が悪いし、SmartLynqはIPアドレスを入れなければならず面倒くさすぎるので、すっかりILAを使う気がなくなってしまいました。
やはりMITOUJTAGに搭載されたBlockRAM型の内蔵ロジアナ(BLOGANA)を使ってデバッグがしたいわけです。
BLOGANAを内包したIPを作ってBlockDesignに張り付けるには一つ問題がります。BlockDesignでのバスの接続は基本的に一対一なので、横から覗き見るようなことができないのです。
でも、ILAみたいにどこにでも接続できるIPを作りたい。
頑張って作りました。それがこのコア↓
ビデオ関係の回路につながっているAXI Liteと、AXI StreamとAXI MMの3つのバスを中に引き込んでいます。
作り方としては以下のようにします。
① まず、ピンの設定はすべてinにします。
② Interface modeの設定では、monitorにします。(mirroredMasterやmirroredSlaveって何につかうんでしょうね)
このような感じで3種類のバスをmonitor設定にしました。
③ これで、ポートに虫眼鏡のマークがついてバスを横から覗き見るポートが作れるようになりました。
上のreset_oという端子は、AXI周辺回路をリセットした直後のバスの動作を見るための出力で、MITOUJTAGのロジアナのコアから信号を出せるようにしています。XILINXのVIOのようなことができます。
実際に動作させて波形を見てみると・・・なんじゃこりゃ!
AXI LiteでVDMAを設定するところの波形がめちゃくちゃです。awvalidを出してawreadyが帰ってきて、wreadyが来ないのに次のawvalidを出しに行っています。それにbrespを待つこともしていない。このvdma_settingsという自作のコアがフライングして動作しているのがいけないようです。
・・いやいや、このコアは自作とはいっても、VivadoのTools→Create and Package New IPで生成したコアですよ。
それなのに、brespはおろか、アドレスVALIDを与える→アドレスREADYを待つ→データVALIDを与える→データREADYを待つ→BRESPを待つというAXIの基本ができていません。ソースを見るとアドレス系とデータ系のステートマシンが別々に存在していて・・・とにかくわかりにくいソースなのです。
これで原因がわかってきました。
Vivado 2017.2のAXI Video DMAは素早く応答してこの滅茶苦茶なAXI Liteアクセスでもうまく動いていたのでしょう。
ところが、Vivado 2019ごろからはAXI Video DMAのリセット後初回の反応が遅くなり、AXI Liteのハンドシェイクをちゃんとしないと正しく書き込みできなくなたのでしょう。だから昔のVivadoでしか動かない回路が出来上がってしまっていたと推測されます。
VivadoのCreate and Package New IPで生成したAXI Liteのペリフェラルは要注意です。
ILAを使ってAXI Streamの信号をデバッグしようとしたら・・
2020.11.18
Video Out回路が動かないので、慣れないながらもILAを使ってデバッグしてみようとしました。
手始めにここのAXI Streamを見てみます。
ところが、Bitgenでエラー発生。
「このようなクロック接続はできない」みたいなことが書いていて逃げ出しそうになるのですが、7シリーズのクロッキングを完全に理解した(はず)なので、エラーメッセージを読んでみました。
[DRC REQP-1975] OSERDES invalid clock topology: Unsupported clocking topology used for OSERDESE2 hdmi_repeater_i/hdmi_out_0/rgb2dvi_0/U0/ClockSerializer/SerializerMaster. This can result in corrupted data. The hdmi_repeater_i/hdmi_out_0/rgb2dvi_0/U0/ClockSerializer/SerializerMaster/CLK / hdmi_repeater_i/hdmi_out_0/rgb2dvi_0/U0/ClockSerializer/SerializerMaster/CLKDIV pins should be driven by the same source through the same buffer type or by a BUFIO / BUFR combination in order to have a proper phase relationship. Please refer to the Select I/O User Guide for supported clocking topologies of the chosen INTERFACE_TYPE mode.
ふむふむ。エラーを起こしているのはDigilentのIPであるrgb2dviだな。
SerializerMasterというOSERDESモジュールの、CLKとDVICLKが別々のクロックソースから供給されていて許されない接続だと言っているようです。確かにOSERDESのクロックはBUFRとBUFIOから供給しなきゃいけませんね。
ではではDeviceのViewを見てみましょう。
なんだこりゃ?CLKDIVがPixelClk_BUFGというネットになってるぞ。こんな信号は使った覚えがない。
rgb2dviのソースをDigilentのgithubからダウンロードして比べてみても変更点はない。
ネットをたどっていくと、下にあるBUFGが勝手に挿入されたようです。
VivadoのプロジェクトフォルダをGREPして調べてみると、
Time (s): cpu = 00:00:17 ; elapsed = 00:00:30 . Memory (MB): peak = 2076.555 ; gain = 111.723 INFO: [Opt 31-389] Phase Sweep created 1 cells and removed 8929 cells INFO: [Opt 31-1021] In phase Sweep, 1173 netlist objects are constrained preventing optimization. Please run opt_design with -debug_log to get more detail. Phase 5 BUFG optimization INFO: [Opt 31-194] Inserted BUFG hdmi_repeater_i/hdmi_out_0/rgb2dvi_0/U0/ClockGenInternal.ClockGenX/PixelClk_BUFG_inst to drive 8 load(s) on clock net hdmi_repeater_i/hdmi_out_0/rgb2dvi_0/U0/ClockGenInternal.ClockGenX/PixelClk_BUFG INFO: [Opt 31-193] Inserted 1 BUFG(s) on clock nets INFO: [Opt 31-1112] Starts optimizing BUFG(s) with a common MMCM/DPLL/XPLL driver. INFO: [Opt 31-1112] Starts optimizing BUFG(s) with a common driver. INFO: [Opt 31-1092] Phase BUFG optimization transformed 0 BUFG(s) to MBUFG(s). Phase 5 BUFG optimization | Checksum: 22d88c4d1
ということだそうです。何勝手に挿入してんねん
Kintex-7でHDMI出力回路
2020.11.17
Kintex-7にHDMI出力回路を入れてDDR3メモリの内容を表示しようと思っているのですが、なかなかうまくいきません。
回路は↑の図のようなもので、DDR3メモリから読み込んだ内容をv_tcやvid_outで表示するというシンプルなものです。Vivado 2017.2で作ったデザインではこれで動いていたはずなのですが、2019.2ではなぜか動きません。Lockがかからないのです。
一番後ろにあるrgb2dviはDigilent製のコアです。設定は以下のとおり。
AXI to Video Outの設定は以下のとおり。
Video Timing Controllerの設定は以下のとおり。
Vivado 2017.2のころとは少し値が違っていたので、Customにして2017.2の設定に合わせます。
AXI Subser Converterは、4バイトのデータを3バイトに切り詰めるためのものです。DDR3メモリからの読み出しデータは32bit単位になっているのですがRGB 8:8:8にするために上位8bitを捨てています。
AXI Video DMAはRead Channelのみ有効にします。
Dynamic Slaveにしておけばタイミングは自動的に作られる・・・はず。(この辺が一番あやしいかな)
Vdma settingsというのは、特電のアルバイトさんが作ってくれたコアで、AXI VDMAの設定をAXI Liteで出力するというものです。
どこからどうみても完璧なのに、なぜ動かないのだ。
HDMI 入力+出力+MIGが入った
2020.11.16
7シリーズのクロックの仕組みを理解してBUFMRやBUFGを置きなおしたら、CLOCK_DEDICATED_ROUTEの制約を付け加えずに、HDMI入力2ch+HDMI出力1ch+MIGが入りました。
LUTの使用率は16%なので、余った領域にHLSで作った回路を追加できそうですね。
DeviceのViewを見てみると、HDMI(DVI)の入出力はほとんどSLICEを使っていないのがわかります。これならHDMIの出力回路をもう1ch付け加えても大丈夫そうですね。同じクロックで動かすのであればクロックリソースを余分には消費しないでしょうし。
7シリーズのクロッキングリソースについて理解する
2020.11.15
作りたい回路は以下のような2chのHDMI入力をデコードするものです。DigilentのZYBOなどでも使われているHDMIのデコーダを2chに改造したものです。
MMCMはFPGA内に全部で8個しかなく、各BankのCMTに1個あると思われますので、この回路をBank16の中だけで作ることはできません。下側のMMCMを別のBankに配置する必要があります。
ユーザガイドug472を読んで、7シリーズのクロッキングリソースについて理解を深めることにします。
- BUFGは32個あるが上下16個ずつにわかれていて、CMTは上半分か下半分のどちらかのグループしか駆動できない
- SRCC,MRCCのピン(bankに4つ)には、1対1で対応するBUFIOがいる
- SRCC,MRCCのピンはBUFRを駆動できる。
- MRCCのピンはBUFMRを駆動できる。
- BUFMRは各bankに2つある
- BUFRは分周もでき、BUFIOと組み合わせて使う。
BUFMRとは何ぞやということですが、自分と隣のbankのBUFRを駆動するためのもののようです。隣のBUFR/BUFIOを駆動する以外には使い道はなさそうです。
BUFRや、BUFMR、BUFIOが何を使って駆動できるかも調べてみましょう。
- BUFIO・・MRCC/SRCC、同一または隣の領域のBUFMR、MMCMの0~3
- BUFR・・MRCC/SRCC、同一または隣の領域のBUFMR、MMCMの0~3、汎用インターコネクト
- BUFMR/BUFMRCE・・同じ領域内のMRCCまたはGTクロック
BUFRとBUFIOが各bankに何個あるかということですが、DeviceのViewを見てみるとおそらく4個ずつあります。
BUFMRは各bankに2個あります。
BUFMRの入力はHCLK_CMT_MUXにつながっているので、実際には様々なソースが使えるのかもしれません。
こうしてみると、何となくMIGでDDR3メモリのデータバスが8個ずつのグループに分かれているのも納得できてきます。
BUFR等の数を再確認しておきます。
- BUFIO・・bankあたり4個
- BUFR・・bankあたり4個
- BUFMR・・bankあたり2個
さて、Backboneとは何かということについてはユーザガイドを見てもよくわからないのですが、デバイス全体を縦に貫いているものであることがわかります。
Backboneが何本あるのかはよくわかりませんが、
Global Clocking Backboneは32本、CMT Clockingも何本かありそうですね。そんなに便利そうなクロック配線なら最初から使わせてくれよと思うのですが、なんでデフォルトで使うようになっていないんでしょうね。やっぱり特性が悪いのかな。
Deviceのビューを見てBackboneに割り当てられている配線を見てみると、
確かにBBとう名前の付く配線を通っていますね。
しかし、Bitgenでエラーが出たほうの配線を見てみると、一般の信号用の配線を通ってしまっています。
もしかすると、BACKBONEを指定しているネットが2個あるからいけないのかもしれません。
XDCでBACKBONEを指定しているクロック配線をFALSEにして再度論理合成してみます。
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk]
これで論理合成が通ってBitgemまで徹ようになりました!
つまり、クロックの性能の良さは専用配線 >BACKBONE > 一般配線 という順序なのですが、専用配線やBACKBONEは制約が大きく使えない場合もあるので、そういう場合はCLOCK_DEDICATED_ROUTE FALSEを指定して一般配線を通しましょうということです。
そもそもこの回路の問題点は、1つのBankで2chのHDMIを入力するところにあります。BankにMMCMは1つしかないので、隣のBankのMMCMを借りてこなければなりませんが、その際のクロック配線が足りなくてBACKBONEを通したりして、いろいろなエラーの元になっていたようです。IBUFDSから隣にBankのMMCMまで行く配線が一般配線を使っているため距離が長くなっていたりもしていました。
そこで、解決策としては、HDMI1とHDMI2で少しクロックバッファの構成を変え、下の図のようにすればよかったようです。
本来、BUFMRはMRCCピンからしか駆動できないようなのですが、なぜかMRCCからも駆動できてしまいました。不思議ですね。CLK_MUXというのがうまく配線を繋ぎ変えてくれているのでしょうか。
ug472を読むと、非推奨ながらインタコネクトからBUFMRを駆動することはできるようです。
一般の配線を通ってしまった信号でもBUFMRを駆動できるようですね。
7シリーズのクロックを完全に理解した気分です。
CLOCK_DEDICATED_BACKBONEのエラー
2020.11.14
ちょっと複雑な回路を作っていると、Vivadoがクロックが引けないとエラーを出してくることがあります。
このデザインはHDMIの2つの入力をミキシングするための回路なのですが、
以下のようないろいろなエラーが出ます。
エラーメッセージの先頭を読むと、
[Place 30-575] Sub-optimal placement for a clock-capable IO pin and MMCM pair. If this sub optimal condition is acceptable for this design, you may use the CLOCK_DEDICATED_ROUTE constraint in the .xdc file to demote this message to a WARNING. However, the use of this override is highly discouraged. These examples can be used directly in the .xdc file to override this clock rule. < set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk] > hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/UseIBUFDS.InputBuffer (IBUFDS.O) is locked to IOB_X0Y76 hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/DVI_ClkGenerator (MMCME2_ADV.CLKIN1) is provisionally placed by clockplacer on MMCME2_ADV_X0Y0 hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/UseIBUFDS.InputBuffer (IBUFDS.O) is locked to IOB_X0Y76 hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/DVI_ClkGenerator (MMCME2_ADV.CLKIN1) is provisionally placed by clockplacer on MMCME2_ADV_X0Y0
となっていて、xdcファイルにset_property CLOCK_DEDICATED_ROUTE BACKBONEを追加すればよさそうなヒントが書かれているので、その通りにやってみます。
すると今度は別のところでエラーが出て
< set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets hdmi_repeater_i/clk_wiz_1/inst/clkfbout_hdmi_repeater_clk_wiz_1_0] >
を追加しろと言ってきます。
そのような感じで言われるがままに制約を追加していって、最終的に
set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets hdmi_repeater_i/clk_wiz_1/inst/clk_in1_hdmi_repeater_clk_wiz_1_0] set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets hdmi_repeater_i/clk_wiz_1/inst/clkfbout_hdmi_repeater_clk_wiz_1_0] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets hdmi_repeater_i/clk_wiz_1/inst/clk_200m_hdmi_repeater_clk_wiz_1_0] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets hdmi_repeater_i/clk_wiz_1/inst/clk_100m_hdmi_repeater_clk_wiz_1_0] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_OUT_5x_hdmi_clk]
ついにRouteは通るようになったのですが、Bitgenでエラーが出るようになってしまいました。
[DRC RTRES-1] Backbone resources: 1 net(s) have CLOCK_DEDICATED_ROUTE set to BACKBONE but do not use backbone resources. The problem net(s) are hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk.
このエラーは、CLOCK_DEDICATED_ROUTEにBACKBONEが指定されたけれども、実際に使用されなかったというエラーです。
XILINXのアンサーAR# 60480で似たようなケースが出ています。このアンサーでは、いったん配線を全部消して、問題となっている配線だけをルーティングし、IS_ROUTE_FIXEDを設定して配線を固定し、再度全配線を行って、get_property route でどの配線を通っているかを調べて、それをXDCに書き出して配線を固定するという超荒業でした。
Tclコンソールで以下を実行します。
open_run impl_1
get_property route [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk]
route_design -unroute
route_design -nets [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk]
set_property IS_ROUTE_FIXED 1 [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk]
route_design
get_property route [get_nets hdmi_repeater_i/clk_wiz_1/inst/clk_in1_hdmi_repeater_clk_wiz_1_0]
{ IOB_IBUF0 LIOI_I0 LIOI_ILOGIC0_D IOI_ILOGIC0_O LIOI_I2GCLK_TOP0 HCLK_CMT_MUX_OUT_FREQ_REF0 HCLK_CMT_FREQ_REF_NS0 MMCM_CLK_FREQ_BB_REBUF0_NS PLL_CLK_FREQ_BB0_NS MMCM_CLK_FREQ_BB_REBUF0_NS PLL_CLK_FREQ_BB0_NS CMT_R_LOWER_B_CLK_FREQ_BB3 CMT_LR_LOWER_B_MMCM_CLKIN1 }
で、この結果から作られたTclの行が
set_property route [get_nets hdmi_repeater_i/hdmi_in_1/dvi2rgb_0/U0/TMDS_ClockingX/CLK_IN_hdmi_clk] { IOB_IBUF0 LIOI_I0 LIOI_ILOGIC0_D IOI_ILOGIC0_O LIOI_I2GCLK_TOP0 HCLK_CMT_MUX_OUT_FREQ_REF0 HCLK_CMT_FREQ_REF_NS0 PLL_CLK_FREQ_BB_BUFOUT_NS0 MMCM_CLK_FREQ_BB_NS0 CMT_R_LOWER_B_CLK_FREQ_BB3 CMT_LR_LOWER_B_MMCM_CLKIN1 }
です。これを追加したら確かに問題の配線はBACKBONEを通るようになったのですが、もうひとつのBACKBONEを指定しているclk_in1_hdmi_repeater_clk_wiz_1_0のほうがBACKBONEを通っていないというエラーが出るようになってしまいました。
やみくもにXDCを追加していってもダメなので、そもそもBACKBONEってなんだ?ってところから調べる必要があるでしょう。
(続く)

































































