Verilog モジュールの記述

verilog

本記事では加算器を例としてVerilogでのモジュールの書き方について説明する.

モジュールの記述

この記事では次の加算器のモジュールを例にして説明していく.
加算器は2進数の入力信号を足し合わせ,結果を出力する.
入力信号のbit数はパラメータにして変更できるようにしている.

module adder #(
    parameter bit_p = 32
) (
    input                 clk_i,
    input                 reset_i,
    input   [bit_p-1:0]   a_i,
    input   [bit_p-1:0]   b_i,
    output  [bit_p-1:0]   z_o
);

    reg [bit_p-1:0] z_r;
    assign z_o = z_r;

    always @(posedge clk_i) begin
        if (~reset_i)
            z_r <= a_i + b_i;
        else
            z_r <= 0;
    end 
endmodule

入出力ポートの宣言

まず,モジュールの宣言をし入出力ポートの宣言を行う.
#マークつきの()内にはビット数など入出力ポートの宣言に必要なパラメータを宣言することができる.

module adder #(
    parameter bit_p = 32
) (
    input                 clk_i,
    input                 reset_i,
    input   [bit_p-1:0]   a_i,
    input   [bit_p-1:0]   b_i,
    output  [bit_p-1:0]   z_o
);

多ビット信号のときは,並びが2進数の向きと同じになる[MSB:LSB]の形で宣言するのが一般的である.
もちろん,[LSB:MSB]でも宣言は可能だ.
また,a_i[2]のようにして信号のあるビット信号を記述できる.



ワイヤ・レジスタの宣言と接続記述

次に必要なワイヤとレジスタの宣言を行う.
今回の例ではレジスタのみだが,ワイヤの例も合わせておく.

    wire [bit_p-1:0] z;
    reg [bit_p-1:0] z_r;

Verilogではwire型とreg型がある.
入出力ポートはワイヤとして扱う.

  • wire : ただのワイヤー,名前の付いた金属配線をイメージ
  • reg : レジスタ,より具体的にはフリップフロップ

ワイヤやレジスタを接続するときにassignを用いる.
assignは配線を繋ぐイメージで使用すれば良い.

    assign z_o = z_r;

クロック同期の記述

多くのディジタル回路はクロックに同期して動作する.
次のようにalways文の中にクロック同期の処理を記述できる.

    always @(posedge clk_i) begin
    // process
    end 

    always @(negedge clk_i) begin
    // process
    end 

    always @(posedge clk_i or negedge clk_i) begin
    // process
    end 

ブロックの記述

begin end はC言語でいう{}に対応し,ブロックの記述に用いる.
begin end内の論理が1行で記述できる場合はbegin endは省略可能である

always文内の記述

次のコードはクロック同期の論理を記述している.
ifやcaseによって条件分岐ができるのはC言語のような通常のプログラムと同様である.

    always @(posedge clk_i) begin
        if (~reset_i)
            z_r <= a_i + b_i;
        else
            z_r <= 0;
    end 

always内ではレジスタに値を代入し,クロックの立ち上がりまたは立ち下りの後の値を決める.
always内での代入には記号<=を用いて代入する.
これはノンブロッキング代入といい,通常のブロッキング代入と違ってコードにおける順序に左右されない代入のことである.

ノンブロッキング代入とブロッキング代入の詳しい説明については次 ↓

Verilog ノンブロッキング代入とブロッキング代入
Verilogではノンブロッキング代入とブロッキング代入を適切に使いわける必要がある.本記事では,ノンブロッキング代入とブロッキング代入について説明する.ノンブロッキング代入とブロッキング代入Verilogでは(<=...

ここで注意したいのはワイヤに値は代入できないことだ.
ワイヤはただの配線金属で数値ではないからである.
では,次のコード(加算器のサンプルコード上部)はどうか

    assign z_o = z_r;

一見,配線に値を代入しているようにも思える.
しかし,assignが配線を接続するイメージで捉えれば,z_rというレジスタの出力とz_oというワイヤを配線していると解釈できる(次の図).
よって,上記のコードは正しいことになり,回路的にはレジスタの出力が駆動側(信号源)として配線の電圧を変化させるということになる.

まとめ

本記事では加算器を例としてVerilogでのモジュールの書き方について書いた.

wireは配線導体,regはレジスタ(フリップフロップ),assignは配線接続のイメージで実際の回路を想像しながら書けるようになると良い.

モジュールを作成した後は,本当に自分が意図した動作になっているか検証を行うテストベンチを作成する必要がある.
次の記事ではテストベンチの書き方について説明する.

次の記事 ↓↓↓

Verilog テストベンチの書き方
Verilogでモジュールを記述した後は本当に論理が合っているか検証が必要であるため,適当な信号を与え出力信号を見るテストベンチが必要である.今回はテストベンチの記述に必要なことをまとめる.テストベンチ記述例先にテストベン...

コメント

タイトルとURLをコピーしました