exits

勉強記録

RTL設計スタイルガイドのアンチパターンをやってみた

はじめに

この記事は 第2のドワンゴ Advent Calendar 2017 の6日目の記事です。

昨日は@urakawaさんでした。

10月から仕事でVerilog HDLを書いています。
↓配属について一瞬だけ触れた記事

学生時代に1週間だけ書いたことはあったんですが、ほとんど入門者状態なので今回はVerilog HDLの勉強的な記事にしようと思います。

RTl設計スタイルガイド

RTL設計スタイルガイド Verilog HDL編
今は絶版になっているようです。
BookWayからPDF版かオンデマンド印刷版を購入できました。

本の中では下の図のようなマーク付きでRTL設計、VerilogHDL記述上の必須、推奨項目が記述されています。
f:id:yue82:20171205224444p:plain
(図はBookWayの立ち読みページからキャプりました)

この記事では、スタイルガイドで必須と言われている項目を守らないとどうなるのかを実際にやってみます。

環境

  • シミュレーション
    • ModelSim Intel FPGA Starter Edition 10.5b
  • 合成
    • Quartus Prime Version 16.1.0 Lite Edition
  • 合成対象
    • Quartus のLite Editionで使えるやつ
    • Family : Arria II GX
    • Device : EP2AGX45CU17C4

アンチパターンをやってみた

スタイルガイドの記述を(たぶん)守っている回路をアンチパターン化してみます。 元となる回路は例題のための適当なものです。

書いたコードはGitHubにまとめています。

組み合わせ回路

functionを使った例

enがhighの時に2bit入力をデコードして4bit出力するモジュールです。

シミュレーション
f:id:yue82:20171206091747p:plain

合成結果

Top-level Entity Name : base_decoder
Family : Arria II GX
Device : EP2AGX45CU17C4
Timing Models : Final
Logic utilization : < 1 %
    Combinational ALUTs : 4 / 36,100 ( < 1 % )
    Memory ALUTs : 0 / 18,050 ( 0 % )
    Dedicated logic registers : 0 / 36,100 ( 0 % )
Total registers : 0
Total pins : 0 / 176 ( 0 % )
Total virtual pins : 7

2.1.1 function文では全ての条件を記述する

条件に抜けを作ってみる。 (rtl/pattern_decoder.v)

diff

@@ -16,4 +16,3 @@
-          2'h3: dec = 4'b1000;

実行結果

VSIM 1> run -all
# DECODE SUCCESS!

テストが通ってしまいましたが実は1個めのテストではoutputはx(不定値)になっています。
f:id:yue82:20171206091008p:plain
if文でテストをしないほうがいいですね。

合成結果

Revision Name : pattern_decoder
Top-level Entity Name : pattern_decoder
Family : Arria II GX
Device : EP2AGX45CU17C4
Timing Models : Final
Logic utilization : < 1 %
    Combinational ALUTs : 3 / 36,100 ( < 1 % )
    Memory ALUTs : 0 / 18,050 ( 0 % )
    Dedicated logic registers : 0 / 36,100 ( 0 % )
Total registers : 0
Total pins : 0 / 176 ( 0 % )
Total virtual pins : 7

ALUが減ったのでラッチ生成などはされていなさそう :thinking_face:

2.1.1 function文内ではノンブロッキング代入文を使用しない

ノンブロッキング代入文にしてみる。 (rtl/non_blocking_decoder.v)

diff

@@ -10,14 +10,14 @@
     begin
       if (en)
         case (in)
-          2'h0: dec = 4'b0001;
-          2'h1: dec = 4'b0010;
-          2'h2: dec = 4'b0100;
-          2'h3: dec = 4'b1000;
-          default: dec = 4'bxxxx;
+          2'h0: dec <= 4'b0001;
+          2'h1: dec <= 4'b0010;
+          2'h2: dec <= 4'b0100;
+          2'h3: dec <= 4'b1000;
+          default: dec <= 4'bxxxx;
         endcase
       else
-        dec = 4'b0000;
+        dec <= 4'b0000;

実行結果

VSIM 1> run -all
# test failed(out!=answer): 0000 != 1000
# test failed(out!=answer): 1000 != 0010
# test failed(out!=answer): 0010 != 0000
# DECODE FAILED (count: 3)

シミュレーション上で代入タイミングが1テンポずれるので、出力がずれてテストが失敗します。

always文を使った例

doAndとdoOrにしたがって4bitのAnd演算またはOr演算をするモジュールです。用途は謎です。

シミュレーション
f:id:yue82:20171205224111p:plain

合成結果

Top-level Entity Name : base_and_or
Family : Arria II GX
Device : EP2AGX45CU17C4
Timing Models : Final
Logic utilization : < 1 %
    Combinational ALUTs : 5 / 36,100 ( < 1 % )
    Memory ALUTs : 0 / 18,050 ( 0 % )
    Dedicated logic registers : 0 / 36,100 ( 0 % )
Total registers : 0

2.2.1 組み合わせ回路のalways文では全ての条件を記述する(ラッチ生成を避ける)

条件に抜けを作ってみる。 (rtl/pattern_and_or.v)

diff

@@ -17,5 +17,6 @@
     end else if (doOr && !doAnd) begin
       out_r = aIn | bIn;
-      isAnd_r = 1'b0;

実行結果

VSIM 1> run -all
# test failed(isAnd!=doAnd): 1 != 0
# AND_OR FAILED (count: 1)

合成結果

Top-level Entity Name : pattern_and_or
Family : Arria II GX
Device : EP2AGX45CU17C4
Timing Models : Final
Logic utilization : < 1 %
    Combinational ALUTs : 4 / 36,100 ( < 1 % )
    Memory ALUTs : 0 / 18,050 ( 0 % )
    Dedicated logic registers : 0 / 36,100 ( 0 % )
Total registers : 0

ラッチは生成されずにただテストが落ちるだけで終わりました。

2.2.2 組み合わせ回路のalways文内の条件式、代入文の右辺信号は全てセンシティビティリストに定義する

センシティビティリストに抜けを作ってみる。 (rtl/sensitivity1_and_or.v)

diff

@@ -13,4 +13,4 @@
-  always @( aIn or bIn or doAnd or doOr ) begin
+  always @( aIn or bIn ) begin

実行結果

VSIM 1> run -all
# test failed(isAnd!=doAnd): 1 != 0
# AND_OR FAILED (count: 1)

aIn, bInが変化せずdoAnd, doOrが変化したときに、always文が実行されないのでテストが失敗します。

2.6.2 always文内で代入されている信号をセンシティビティリストに記述しない

センシティビティリストに文内で代入される信号を書いてみる。 (rtl/sensitivity2_and_or.v)

diff

@@ -13,4 +13,4 @@
-  always @( aIn or bIn or doAnd or doOr ) begin
+  always @( aIn or bIn or doAnd or doOr or out_r or isAnd_r ) begin

実行結果

VSIM 1> run -all
# AND_OR SUCCESS!

この例ではテストが通ります。
合成結果

Family : Arria II GX
Device : EP2AGX45CU17C4
Timing Models : Final
Logic utilization : < 1 %
    Combinational ALUTs : 5 / 36,100 ( < 1 % )
    Memory ALUTs : 0 / 18,050 ( 0 % )
    Dedicated logic registers : 0 / 36,100 ( 0 % )
Total registers : 0

合成結果も変わらなかった・・・ でもout_risAnd_rが変わったらalways文に入るので下手するとバタバタしそうですね。

順序回路

順序回路の例

2つの入力の差分を取り、4サイクル後に出力するモジュールです。

シミュレーション
f:id:yue82:20171206091804p:plain

合成結果

Top-level Entity Name : base_sub_later
Family : Arria II GX
Device : EP2AGX45CU17C4
Timing Models : Final
Logic utilization : < 1 %
    Combinational ALUTs : 5 / 36,100 ( < 1 % )
    Memory ALUTs : 0 / 18,050 ( 0 % )
    Dedicated logic registers : 23 / 36,100 ( < 1 % )
Total registers : 23
Total pins : 1 / 176 ( < 1 % )
Total virtual pins : 14

+-----------------------------------------------------------------------------------------------------------+
; Slow 900mV 85C Model Fmax Summary                                                                         ;
+------------+-----------------+------------+---------------------------------------------------------------+
; Fmax       ; Restricted Fmax ; Clock Name ; Note                                                          ;
+------------+-----------------+------------+---------------------------------------------------------------+
; 846.02 MHz ; 260.01 MHz      ; clk        ; limit due to minimum period restriction (max I/O toggle rate) ;
+------------+-----------------+------------+---------------------------------------------------------------+

2.3.2 ノンブロッキング代入文とブロッキング代入文を混在させない

ノンブロッキング代入を前提とした回路をブロッキング代入に変更してみる。 (rtl/blocking_sub_later.v)

diff

@@ -15,8 +15,8 @@
   always @( posedge clk ) begin
-    a_r <= aIn;   b_r <= bIn;
-    sub1_r <= a_r - b_r;
-    sub2_r <= sub1_r;
-    sub3_r <= sub2_r;
+    a_r = aIn;   b_r = bIn;
+    sub1_r = a_r - b_r;
+    sub2_r = sub1_r;
+    sub3_r = sub2_r;

実行結果

VSIM 1> run -all
# test failed(subOut!=answer):   0 !=   4
# test failed(subOut!=answer):   0 !=  -3

遅延用のシフトが正しく行われないのでテストが失敗します。

2.10.6 符号付き演算ではビット幅の指定、ビット結合をしない

符号付きの信号でビット幅指定をしてみる。 (rtl/signed_sub_later.v)

diff

@@ -13,4 +13,4 @@
-  reg signed [5-1:0]    sub3_r;
+  reg signed [6-1:0]    sub3_r;
 
@@ -22,3 +22,3 @@
-  assign subOut = sub3_r;
+  assign subOut = sub3_r[4-1:0];

実行結果

VSIM 1> run -all
# test failed(subOut!=answer):  13 !=  -3
# SUB FAILED (count: 1)

符号なしとみなされてテストが失敗します。

所感

意外とテストも通ったり合成でも変わらなかったりしました。 例が悪かった気もします :pray:

明日は@nagisioさんです!