gowin-oser10-evaluation-part-1

Gowin の OSER10 検証 その1

Tang Nano 9K で DVI-D 信号を生成したいと思い、ciniml さんの表示回路(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ビットずれる

期待結果とのずれ

OSER10 は LSB から順に出力するはずです。しかし観測結果を見ると信号がずれていることが分かります。観測結果に期待結果を重ねてみると次図のようになります。実際の出力が期待結果より 6 クロック分遅れています。

10Hzで駆動したOSER10で6ビットずれる様子と期待結果

考察

OSER10 を使ってみたのは今回が初めてというのもあり、原因について全然想像が付きません。もしかしたら OSER10 に供給するクロックの生成を自前のカウンタでやっているのが悪いのかもしれませんし、そもそもクロックが遅すぎるとダメだったりするのかもしれません。

これから原因を探っていこうと思います。「その 2」以降の記事が書けるかどうか、検証の進み具合に乞うご期待!

検証に用いたコード

最後に、検証に用いたコードを紹介しておきます。初めて Veryl というハードウェア記述言語を使ってみました。

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,
  );
}


この記事は以下の記事から参照されています。

作成:2025-12-23 10:45:38

最終更新:2025-12-23 10:45:38