Verilog-HDL 文法(4):組み合わせ,順序回路記述
2015/09/27
[CategoryTop] [Prev] [Next]
[目次]・組合せ回路記述
     + assign
     + function
     + always
   ・順序回路記述
     + always
   ・moduleコール
     + module

●組合せ回路記述

 ◆assign
 
  ・assign継続的代入(continuous assignments)を意味します。主に演算子の結合で
   記述できる簡単な組合せ回路の定義
に用います。
  
  ・平たく言ってしまえば、常に接続され、変化に追従する信号です。故にこの後説明
   するalwaysやinitial等の手続き型(procedural)ブロックと並列(独立)に記述されま
   す。
  
  ・assignが使用できるノードはネット型のみです。つまりwire宣言した信号(ポートは
   省略されているがwire型)にはassignを記述できますが、reg型には適用できません。
  ┌─────────────────────────────────────┐
   assign z = ~(a & b);      // NAND
   assign z = (sel == 1)? a1 : a0; // Selector(MUX)
  └─────────────────────────────────────┘
  
  ・通常は、上記のように assign が明確に記述されることで「継続的代入」を定義し
   ますが、wire定義時に以下のような「暗黙の継続的代入」記述が可能です。
  ┌─────────────────────────────────────┐
   wire mux_out = (sel)? a1 : a0;
  └─────────────────────────────────────┘
  
  ・ただし、RTLを記述する担当と検証の担当が別々の場合、記述の方法が複数あると混
   乱の元になるので、前者(explicitなassign記述)で統一するのがお勧めです。ちょ
   っとした確認のために使う小技だと思っていた方が良いでしょう。
  
  ・また、シミュレーション記述で再度説明しますが、assign文ではディレイを記述
   ることができます。下記の例はメモリ読み出しにディレイを付けたイメージです。
  ┌─────────────────────────────────────┐
   parameter RDELAY = 500;
   assign #RDELAY data = (out_en)? sram[addr] : 16'hz;
  └─────────────────────────────────────┘


 ◆function
 
  ・functionは、assignでは記述できない複雑な論理(回路規模ではない)を記述すると
   きに用います。functionは大まかに以下の構成を持ちます。
  ┌─────────────────────────────────────┐
   function [レンジ] function_name;
     入力ネット名;
     ローカルレジスタ名;
     ステートメント
   endfunction
  └─────────────────────────────────────┘
  
  ・このようにして定義したfunctionをネットにassignし、moduleに組み込みます。
  
  ・ステートメントには以下を使用することができます。(論理合成可能な組合せ回路記
   述だけを意識した内容です)
  ┌─────────────────────────────────────┐
   * begin 〜 end
    | beginからendで囲まれた複数の演算式を順番に実行します。結果的に1個のブ
    | ロックを形成します。ブロック内では下記のステートメントを使用することが
    | できます。
    | 
    +-- =演算子
    |   ブロッキング代入です。begin〜endブロックでブロッキング代入演算子が
    |   使用されている場合、演算は上から順番に行われます。
    |
    +-- if ブロック 又は if ブロック else ブロック
    |   条件分岐です。下記のように記述します。
    |    if (sel == 1)
    |      z = a1;
    |    else
    |      z = a0;
    |
    +-- case
    |   case文です。下記のように記述します。マッチ条件とステートメントの並
    |   びです。ステートメントは更にブロック記述が可能です。
    |     case (in)
    |       2'b00  : dec = 4'b0001;
    |       2'b01  : dec = 4'b0010;
    |       2'b10  : dec = 4'b0100;
    |       2'b11  : dec = 4'b1000;
    |       default : dec = 4'bxxxx;
    |     endcase
    |
    +-- casez
    |   マッチ条件に「z」を含めることができます。
    |
    +-- casex
       マッチ条件に「x」又は「z」を含めることが可能です。
  └─────────────────────────────────────┘

  ・functionで記述したデコーダ記述例を示します。
  ┌─────────────────────────────────────┐
   module decoder_2_4 (in, out, en);
     input [1:0] in;
     input    en;
     output [3:0] out;
     
     //-------------------------------------
     function [3:0] dec;
       input [1:0] in;
       input en;
       
       begin
         if (en == 1)
           case (in)
            2'b00  : dec = 4'b0001;
            2'b01  : dec = 4'b0010;
            2'b10  : dec = 4'b0100;
            2'b11  : dec = 4'b1000;
            default : dec = 4'bxxxx;
           endcase
         else
           dec = 4'b0000;
       end
       
     endfunction
     //-------------------------------------
     
     assign out = dec(in, en);
     
   endmodule
  └─────────────────────────────────────┘
  
  ・functionで組合せ回路を記述する場合の注意点です。潜伏するエラーとなるので間
   違いを発見しにくくなっています。
  
    + 引数の不一致
      * 今回の例で示したdec functionの引数はin, enですが、引数を書き忘れた
       場合、コンパイラによってはエラーを検出しない
ことがあります。
      
      * bit数が異なる場合(特にfunction内の信号bit数が少ない)、エラーは検出
       されません。
       
      * 引数の記述順は、function内での入力信号定義順です。引渡しの記述順を
       間違えてもエラーは検出されません。
(違う値が引き渡されてしまう)
    
    + マッチ条件の未記述
      * functionの場合、後述のalwaysのようにマッチ条件を全て書かなくても論
       理合成結果でラッチが生成されることはありませんがシミュレーションで
       はラッチがあるように動く
ので、RTLレベルとゲートレベルでシミュレーシ
       ョンミスマッチを起こすことがあります。


 ◆always
 
  ・alwaysは一般的に順序回路記述に使用されますが、組合せ回路を記述することも可
   能
です。alwaysは以下の構成を持ちます。
  ┌─────────────────────────────────────┐
   always @ (条件信号リスト) ステートメント
  └─────────────────────────────────────┘
  
  ・組合せ回路を記述する場合、使用するステートメントはfunctionで紹介したものと
   同じです。

  ・alwaysで記述したデコーダ記述例を示します。
  ┌─────────────────────────────────────┐
   module decoder_2_4 (in, out, en);
     input [1:0] in;
     input    en;
     output [3:0] out;
     
     //-------------------------------------
     reg  [3:0] out;
     always @ (in or en) begin // 複数信号は論理和
       if (en == 1)
         case (in)
          2'b00  : out = 4'b0001;
          2'b01  : out = 4'b0010;
          2'b10  : out = 4'b0100;
          2'b11  : out = 4'b1000;
          default : out = 4'bxxxx;
         endcase
       else
         out = 4'b0000;
      end
      //-------------------------------------
     
   endmodule
  └─────────────────────────────────────┘
  
  ・always文で組合せ回路を記述する場合ですが、alwaysブロック内でセンスする信号
   条件の書き漏れがあった場合、論理合成時にラッチが生成されます。
この結果シミ
   ュレーションでミスマッチが発生します。
  
  ・さて、functionとalwaysのどちらで組合せ回路を記述すべきかという問題ですが、
   両方とも記述ミスがあるとシミュレーションミスマッチが発生するのは同じという
   意味で、以下の条件で選択されると思っています。
  ┌─────────────────────────────────────┐
    + ローカルで使用する文法チェッカの検出率が高い方
    + 順序回路記述と組合せ回路記述を明確に分けたければ、function使用
    + VHDLとの混合が考えられるのであれば、always使用
  └─────────────────────────────────────┘
  
  ・ちなみに私(Monpe)は自分の周りに合わせてfunction派です。


●順序回路記述

 ◆always
 
  ・順序回路の記述にはalwaysを使用します。組合せ回路のalwaysと基本は変りませんが
   タイミングに関するステートメントが追加されます。これらのステートメントは
   functionで使用することはできません。
   ┌─────────────────────────────────────┐
    + always @ (エッジ 信号) ステートメント
      * 信号の立上りエッジ(posedge)又は立下りエッジ(negedge)に同期した記述
       です。
       (例)always (posedge CLK or negedge RESET) 〜
    
    + <= 演算子 : ノンブロッキング代入
      * 本来begin〜endブロック内は順次実行ですが、ノンブロッキング代入を指
       定した場合、並列に実行されます。

       (例)reg1 = 0, reg2 = 1の場合
          reg1 <= reg2;
          reg2 <= reg1;
         値がスワップされる。reg1の値が評価される前に代入するから。順次
         実行のブロッキング代入と異なる点に注意。
    
    + ディレイの付加
      * 代入の左辺又は右辺にディレイを付加できる。
      * ブロッキング/ノンブロッキングは問わない。
       (例)q <= #DELAY d;
  └─────────────────────────────────────┘
  
  ・alwaysで記述したラッチ、フリップフロップの例を示します。
  ┌─────────────────────────────────────┐
   `define DELAY_UNIT 1 //ディレイ値のマクロ定義
   
   module dff_res_async (ck, d, q, res); //クロック非同期リセットのFF
     input ck;
     input d;
     input res;
     output q;
     reg  q;
     
     parameter DELAY = `DELAY_UNIT; //ディレイ値パラメータ定義
     
     always @ (posedge ck or posedge res) begin //エッジセンシティブ
       if (res)
         q <= #DELAY 1'b0;
       else
         q <= #DELAY d;
     end
   endmodule

   module dff_res_sync (ck, d, q, res); //クロック同期リセットのFF
     input ck;
     input d;
     input res;
     output q;
     reg  q;

     parameter DELAY = `DELAY_UNIT;
     
     always @ (posedge ck) begin
       if (res)
         q <= #DELAY 1'b0;
       else
         q <= #DELAY d;
     end
   endmodule
   
   module h_latch (g, d, q); //レベルセンシティブ : ラッチ
     input g;
     input d;
     output q;
     reg  q;

     parameter DELAY = `DELAY_UNIT;
     
     always @ (g or d)
       if (g)
         q <= #DELAY d;
   endmodule
   └─────────────────────────────────────┘

  ・上記の例で `define と parameter を使用しました。`define はコンパイラ指示子
   でマクロを定義しています。parameterはネット型やレジスタ型以外の定数データを
   扱うためのデータ型です。
  
  ・parameter DELAY をノンブロッキング代入の遅延として使用しています。このDELAY
   に与える数値をマクロ定義しています。もしディレイ値を正確に設定したければマ
   クロを変更するだけで済むからです。


●moduleコール

 ◆module
 
  ・回路の規模が大きくなれば、moduleを分割して設計を行います。つまりVerilog-HDL
   のmoduleは階層構造を持ちます。
  
  ・これにはいくつかの理由があります。
    + 設計の分業化による効率向上(分割統治)、検証も効率Up
    + 回路の単位規模を論理合成の範囲内に収める
  
  ・モジュールが小さい(大き過ぎない)場合、論理合成後はmoduleの階層を解いて、チ
   ップ化するのに最適な分割を行うことができます。つまり、moduleの構成はあくま
   で論理的な階層を意識すればOKです。(*1)
  
  ・moduleの呼出は以下の書式で行います。
   ┌─────────────────────────────────────┐
    モジュール名 インスタンス名 (ポートリスト);
   └─────────────────────────────────────┘
  
  ・ポートリストにはmoduleでのポートリスト定義順に接続信号を並べる方法と、定義
   側ポート名を明記する方法
があります。
   ┌─────────────────────────────────────┐
    module sample (ck, data, re, we);
   
    // 記述例1 - 定義順に並べる
    sample sample_i1 (clk, data1, read_en, write_en);
    // 記述例2 - 接続ポートの明記
    sample sample_i2 (.ck(clk), .re(read_en), .data(data1), .we(write_en);)
   └─────────────────────────────────────┘
  
  ・尚、呼出す同種モジュールが1つだけの場合、インスタンス名とモジュール名は同一
   にする
ことができます。
  

(*1)いくらでも小さくして良いというわけでもありません。この辺りは別の場(もう少し進
  んでから)で話をしたいと思います。

[Revision Table]
 |Revision |Date    |Comments
 |----------|-----------|-----------------------------------------------------
 |1.00   |2003-11-18 |初版
 |1.01   |2003-11-24 |リンク追加
[end]

Copyright(C) 2015 Altmo