エレファイン

Verilog モジュール


Numato Lab社のサイトより引用・翻訳


Verilogはディジタル回路を扱います。
Verilogの中では、シンプルなゲートから、ALU、メモリーなどといった複雑なものまでモジュールは、ディジタル回路中のコンポーネントと見なすことができます。モジュールは、自己完結している場合と、有限の数を外部と対話する方法(ポート)がある点においては、C++のクラスにある意味では似ています。
C++でクラスをインスタンス化するように、モジュールもインスタンス化できます。しかし、注意が必要です。それが実装されるとき、モジュールは、クラスと100%同じにはなりません。
モジュールは、単に多くのポートを備えた箱として図に表わすことができます。
ポートは入力、出力、あるいは双方向として使うことができます。ポートのデータ幅は、単一ビットあるいは、複数ビットとしても使えます。
下図は、少数の入力および出力を備えたモジュールを表わします。
入力と出力の数、それらの幅および方向は、もっぱらモジュールの機能性に依存するでしょう。

ポートは、入力または出力または双方向にすることができます。基本的にVerilogでは、モジュールを作成し、それらを相互接続と相互作用のタイミングを管理することがすべてです。

本題に入りましょう。私たちは、まだ 、"Hello World"プログラムさえも作っていません。
では、どのようにして、Verilogに手を染めるのでしょうか。
それでは、VerilogのNOTゲートを設計し、それをシミュレートし、実際のハードウェアでテストしてみましょう。
NOTゲート(別名インバーター)は、すべてのゲートの中での最も簡単なゲートでしょう。インバーターの出力は常に入力の否定です。すなわち、Aを入力、Bを出力とした場合、B =!A となります。
下図にNOTゲートの動作を真理値表として要約します。

入力
A
出力

B = NOT A
0
1
1
0

NOTゲートは、B = !A の内部動作と1つの入力と1つの出力を持つモジュールとして考えることができます。
下記のインバーターモジュールのグラフィカルな表現を参照してください。


Verilogでこれを表現する方法を見てみましょう。

 1.module myModule(A, B);

 2.   input wire A;

 3.   output wire B;

 4.   assign B = !A;

 5.endmodule



とても単純ではありませんか。それぞれの行を見て、各コードで何をしているのかを理解してみましょう。
モジュールの名前は "MyModule"で、 "module"というキーワードを使用して宣言されています。Verilogのmoduleキーワードは、myModuleというモジュールを定義し、2つのポートを割り当てます。このモジュールに含まれるすべてのものは、 "module"と "endmodule"のキーワードの間に配置されます。myModuleは、各1ビット幅の2つのポートがあります。ポートの大きさや方向は、この段階では、まだわかりません。
2行でポートAおよびポートBは、それぞれ入力および出力として宣言しています。"wire"が何を意味するか疑問に思うことでしょう。さて、Verilogでは、2つの基本のデータ・タイプ、wire および reg があります。int、real のようにほかにも多くのデータ・タイプがあります。しかし、wire と reg は、それらを学習しないとぜんぜん進まないと言えるほど、Verilogにおいて非常に重要な役割を果たします。
前に述べたように、少しデジタルエレクトロニクスを知っていることは、ここで役に立ちます。wire は、ちょうど電気的に2つの異なるものを接続するために使用する物理的なワイヤー(電線)のようになります。電位が電線の一端に印加されている場合、印加続ける限り、電線に電位が存在することになります。入力を切ると、すぐに電位がなくなります。これは、Verilogの wire の場合も同様です。それが他のエンティティによって駆動される限り、特定のロジック状態を持ちます。何からもワイヤーが駆動されていない場合、それは未知の状態になります。Verilogでは、 wire は、モジュール内、または2つのモジュール間を接続するために使用することができます。
一方、 reg は、何かが変更を行う(マイクロコントローラー内のレジスタと同じと考える)までロジック状態を保存し、維持することができます。これは、フリップフロップに似ています。フリップフロップをある状態にした場合、それは何かが変更を行うまで、それまでその状態のままになります。

よって、モジュールの入力または出力として、wire を使用することができ、 reg はモジュールの出力として使用することができます。wireを出力として使用する場合は、そのwire上に有意義な情報を持たせるためにモジュール内から wire を駆動する reg があるはずです。reg は、出力として使用されている場合は、それ自身のデータを保持することができるので、他のメカニズムは必要ありません。
ところで、"myModule"は、入力と出力の両方とも、wire として宣言したのでしょう?いい質問ですね。
答えは、「モジュールは、NOTゲートを表すから」です。ゲートは、任意の状態を保存することはありません。ゲートは、純粋な組み合わせであり、その出力は常に入力電流に依存します。すなわち、その入力に印加されたロジック状態がある場合は、対応する出力(この場合、B =!A)があります。ロジック状態が入力に印加されていない場合、それは未知の状態とみなされ、出力状態は不明になります。また、これは、このモジュールからの有効な出力を得るために、ほかのエンティティからその入力を駆動すべきであることも示唆します。(このことを覚えておいてください。後でテストベンチについて説明するとき、この件に触れます。)

上記のコードに関するもう一つ重要なことは、キーワード "assign"です。assign は、組合せ回路を作成するために使用されています。文の等号の右側に書かれたものは何でも評価され、その結果が左側のエンティティに割り当てられ、これが非同期で行われます。変更が右側に起こるとすぐに、結果は左側に反映されます。もし、このことが理解するのが難しいと感じたらデジタル回路について少し読むことをお勧めします。

今、1個のコードがあるので、それが予想通りに作動しているかどうか確かめるためにコードをシミュレートしたいと思うかもしれません。シミュレーションは、広い意味で、ある既知入力を与えて、出力を生成するプロセスです。
出力が予期された出力に対して確認できた場合、それはベリファイ(ベリファイケーション、検証)と呼ばれます。
シミュレーションとベリファイに利用可能な多くのツールがあります。
ここでは、iSim(ザイリンクスISE Webpackの一部)をシミュレーションおよび波形確認に使用します。


続編は、随時追加します。


このページの先頭に戻る

Spartan3A FPGAボード