uchanのアイコン画像
uchan 2021年12月13日作成
セットアップや使用方法 セットアップや使用方法 閲覧数 1633
uchan 2021年12月13日作成 セットアップや使用方法 セットアップや使用方法 閲覧数 1633

FPGAの論理演算は遅延するらしい

FPGAの論理演算は遅延するらしい

FPGA で AND 等の論理演算が若干遅延することを実際に観測してみました。

実験設定

使用した FPGA ボードは Tang Nano 4K です。

実験のために以下のような Verilog プログラムを作りました。raddrrx_v が今回観測したい信号で、それぞれ条件演算子および AND 演算子が使われています。assign は継続代入というもので、右辺の信号のいずれかが変化するたびに代入が行われます。

信号の定義

wire [7:0] rdata; wire [2:0] raddr; wire rx_v; reg rx_en, rdata_v, rx_rdy, blank_rd; assign raddr = rx_rdy ? 0 : 5; // 今回注目する信号(条件演算子) assign rx_v = rdata_v & rx_rdy & ~blank_rd; // 今回注目する信号(AND 演算子) // rx_en, rdata_v, rx_rdy, blank_rd はいずれも // always 文でのノンブロッキング代入により変化する always @(posedge sys_clk) begin if (!rst_n) rx_en <= 1'd0; else rx_en <= ~rx_en; // rx_en は clk を 2 分周した波形 end always @(posedge sys_clk) begin if (!rst_n) rdata_v <= 1'd0; else rdata_v <= rx_en; // end always @(posedge sys_clk) begin if (!rst_n) rx_rdy <= 1'd0; else if (rdata_v && raddr == 5 && rdata[0]) rx_rdy <= 1'd1; else if (rdata_v && rx_v) rx_rdy <= 1'd0; end always @(posedge sys_clk) begin if (!rst_n) blank_rd <= 1'd0; else if (rdata_v && raddr == REG_LSR && rdata[0]) blank_rd <= 1'd1; else if (rdata_v) blank_rd <= 1'd0; end

波形の観測は Gowin Analysis Oscilloscope で行いました。これは Gowin の FPGA に特有の測定機能で、FPGA の内蔵メモリに波形データを記録し、PC に転送して画面に表示してくれます。波形データは設定したクロックのエッジで記録できます。今回は sys_clk および sys_clk を PLL で 4 倍にしたクロックの立ち上がりエッジで波形を記録させました。

sys_clk は 27MHz を PLL で 13/7 倍した 50.143MHz です。「sys_clk を PLL で 4 倍にしたクロック」は 27MHz を 52/7 = 4×13/7 倍した 200.571MHz です。

実験結果

観測された波形を示します。

観測波形

まず sys_clk で記録した波形に注目します。見ての通り sys_clk(一番上の信号)は常に 0 で記録されています。立ち上がりエッジの直前の信号レベルで記録されるということですね。

2 行目の信号 I_RX_EN には rx_en が接続されているので、I_RX_ENrx_en は等価だと思っていただいて大丈夫です。同様に 3 行目、4 行目の信号 I_RADDRO_RDATA にはそれぞれ 、raddrrdata が接続されており、それぞれ等価と思ってください。

rx_ensys_clk の立ち上がりエッジのタイミングで反転するので、sys_clk をちょうど 2 分周した信号となります。

rdata は、黄色い縦線のタイミングで 5→0 に変化しています。sys_clk の立ち上がりエッジに合わせて、一瞬で 5→0 に変わったかのように観測されています。

遅延の考察

次に図の下半分(sys_clk の 4 倍のクロックで信号を記録した場合)に注目します。4 倍のクロックでサンプリングしたため、sys_clk の変化も捉えることができています。

先ほどと異なるのは、rx_enraddr の変化タイミングの違いです。rx_en は依然として sys_clk の立ち上がりエッジと同じタイミングで変化しているものの、raddr は少し遅れて変化しています。

sys_clk の 4 倍のクロックでしか記録をしないので、実際の遅れ幅は確定できません。ただ、少なくとも sys_clk の周期の 1/4(5ns 程度)以上は遅延していると判断できると思います。(sys_clk の周期の 1/4 より短い遅延は観測できないと筆者は認識していますが、間違っていたらコメントください)

rx_v について見てみます。上の図では後半に山が 1 つだけ見えますが、下の図では山が 2 つ観測されました。先ほどの大きな山の前に、小さな山が出現したのです。

rx_v の右辺は rdata_v & rx_rdy & ~blank_rd; ですから、rdata_v=0 のときは rx_v=0 になるはずです。しかし、この小さな山のタイミングでは rdata_v=0 になっているにもかかわらず、rx_v=1 となっています。単に「信号が遅れている」だけでなく、プログラム上起きないはずの不整合な状態になっていることが分かりました。

uchanのアイコン画像
本業はプログラマですが、昔から電子工作は趣味でやってます。初めてのプログラミング言語はPICアセンブラです。 モジュールを買ってきて組み合わせるだけでなく、部品の動作原理をきちんと理解して回路を設計することに楽しさを感じます。 2021年より「uchanの電子工作ラボ」という施設を運営しています。はんだごてや測定器が使えます。 https://uchan.net/lab/ 2021年3月22日に「ゼロからのOS自作入門」を出版しました。Amazon→ https://amzn.to/2NP3FUj
  • uchan さんが 2021/12/13 に 編集 をしました。 (メッセージ: 初版)
ログインしてコメントを投稿する