編集履歴一覧に戻る
uchanのアイコン画像

uchan が 2025年12月25日22時44分20秒 に編集

初版

タイトルの変更

+

Gowin の OSER10 検証 その1

タグの変更

+

Tang-Nano

+

FPGA

+

DVI

+

Veryl

+

verilog

記事種類の変更

+

セットアップや使用方法

本文の変更

+

Tang Nano 9K で DVI-D 信号を生成したいと思い、[ciniml さんの表示回路(display_controller)](https://github.com/ciniml/fpga_samples/tree/gowin_vol5/eda/display_controller) のソースコードを読んでいます。最終的な DVI-D 信号の生成に OSER10 という FPGA プリミティブを使っていることが分かったので、その動作を実際に確かめてみようと思います。 ## OSER10 の使用箇所 ciniml 氏の回路において OSER10 を使用しているのは次の行です。8 ビットの映像データが TMDS 処理を経て 10 ビットになったものを OSER10 でシリアライズしています。 https://github.com/ciniml/fpga_samples/blob/d5bf6f3f032de09d8fd7d37ee3a1c38765ce1b29/eda/display_controller/src/tangnano9k/top.veryl#L366 ## 波形の観測 OSER10 を使う回路を適当に作り、固定値 `10'b00_1111_0001` を出力させてみました。その結果を次に示します。fclk は 5Hz、pckl は 1Hz のクロックで、oser_out が OSER10 の出力です。 ![10Hzで駆動したOSER10で6ビットずれる](https://camo.elchika.com/630d7f600f0da11cc584b245cc3c827add2cde78/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f63333936313234302d643365342d346361652d396632662d3965396366383634616562342f62303133336630342d656366662d343463662d623663352d663966656233636562306332/) ## 期待結果とのずれ OSER10 は LSB から順に出力するはずです。しかし観測結果を見ると信号がずれていることが分かります。観測結果に期待結果を重ねてみると次図のようになります。実際の出力が期待結果より 6 クロック分遅れています。 ![キャプションを入力できます](https://camo.elchika.com/422851f660607bbaf32a64add877db4d7a80d6ed/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f63333936313234302d643365342d346361652d396632662d3965396366383634616562342f65323137666564382d336138382d343563322d383634302d383730373430666562383637/) ## 考察 OSER10 を使ってみたのは今回が初めてというのもあり、原因について全然想像が付きません。もしかしたら OSER10 に供給するクロックの生成を自前のカウンタでやっているのが悪いのかもしれませんし、そもそもクロックが遅すぎるとダメだったりするのかもしれません。 これから原因を探っていこうと思います。「その 2」以降の記事が書けるかどうか、検証の進み具合に乞うご期待! ## 検証に用いたコード 最後に、検証に用いたコードを紹介しておきます。初めて [Veryl](https://doc.veryl-lang.org/book/ja/) というハードウェア記述言語を使ってみました。 ```SystemVerilog module top( sys_clk: input clock, rst_n_raw: input reset_async_low, onboard_led: output logic<6>, oser_fclk: output logic, oser_pclk: output logic, oser_out: output logic, ) { var pre_scaler : u32; var counter : u32; var lchika : logic; var oser_in : logic<10>; var oser_clk_cnt : u8; const PRE_SCALE : u32 = 27_000_00; assign onboard_led = ~counter[5:0]; always_ff (sys_clk, rst_n_raw) { if_reset { pre_scaler = 0; } else if (pre_scaler == PRE_SCALE - 1) { pre_scaler = 0; } else { pre_scaler += 1; } } always_ff (sys_clk, rst_n_raw) { if_reset { counter = 0; } else if (pre_scaler == PRE_SCALE - 1) { counter += 1; } } always_ff (sys_clk, rst_n_raw) { if_reset { oser_clk_cnt = 0; oser_fclk = 0; oser_pclk = 0; } else if (pre_scaler == PRE_SCALE - 1) { oser_fclk = ~oser_fclk; if (oser_clk_cnt == 4) { oser_clk_cnt = 0; oser_pclk = ~oser_pclk; } else { oser_clk_cnt += 1; } } } assign oser_in = 10'b00_1111_0001; inst oser10_1: $sv::OSER10 #( GSREN: "false", LSREN: "true" ) ( Q: oser_out, D0: oser_in[0], D1: oser_in[1], D2: oser_in[2], D3: oser_in[3], D4: oser_in[4], D5: oser_in[5], D6: oser_in[6], D7: oser_in[7], D8: oser_in[8], D9: oser_in[9], FCLK: oser_fclk, PCLK: oser_pclk, RESET: ~rst_n_raw, ); } ```