Verilog-HDLに触れてみよう

調べものをしていた時、たまたまVerilog-HDLという言語を知りました。
あまり耳にしない言語を知ると使ってみたくなります。ということで、Verilog HDLやっていきましょう。

#始める前に
私は回路についてまともに勉強したことないのでそういった知識はありません。どちらかといえば情報系の人間なので記事を書くにあたって説明不足な点が多々あると思います。なのでこの記事では、Verilog HDLを学ぶのではなく触れてみようくらいの気持ちで読んでください。
verilog HDLのコンパイラはHomebrewを使用してインストールするので、Homebrewのインストール方法から書きます。

#Verilog HDLってなに？
ハードウェア記述言語の一種です。HDLと呼ばれ、Hardware Description Languageの略称です。
HDLはプログラミング言語とは別物として扱われます。処理的な違いはありますが、使われ方も違います。プログラミング言語が完成形のものを作る言語であれば、HDLは論理回路を設計する言語です。家の設計はCAD, 論理回路の設計はHDL, プログラミングの設計はUMLがニュアンス的に似ていると思います。
HDLは、VHDLとVerilog HDLの二つの言語が業界の主流として扱われています。今回はその中のVerilog HDLを触っていきます。
*以降、Verilog HDLをVerilogと呼びます。

#開発環境
macOS Catalina 10.15.1
Homebrew 2.2.0
Icarus Verilog 10.3

#環境構築
以下をインストールします。
・Homebrew （macOS用パッケージマネージャー）
・Icarus Verilog （コンパイラ＆シミュレータ）
・GTKwave （波形描画ソフト）

##Homebrew インストール
まず、App StoreからXcodeをインストールしてください。
インストールできたら以下のコマンドをターミナルから実行して環境構築を行なってください。

1.Xcode Command Line Toolsのインストール
```$ xcode-select --install
```

2.Homebrewのインストール
最新のコマンドは、[こちら](https://brew.sh/index_ja)を参照してください。
```$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

以下のように入力してバージョンが表示されたらインストール完了です。
```$ brew -v
```

##Icarus Verilog インストール
インストールしたHomebrewを使用します。
```$ brew install icarus-verilog```

以下のコマンドでインストールの確認をしてください。
いろいろ表示されますが、実行したコマンドの一行下にバージョンが書かれています。
```$ iverilog -V```

##GTKwave インストール
同じく、Homebrewを使用します。
```$ brew install caskroom/cask/gtkwave```

コマンドを実行した時、以下のどちらかのエラーが出る場合があります。

下のエラーが出た場合・・・

```terminal
Error: Cask ‘gtkwave’ requires XQuartz/X11, which can be installed using Homebrew Cask by running
```
```$ brew cask install xquartz```
```$ brew install caskroom/cask/gtkwave```

下のエラーが出た場合・・・

```terminal
Error: caskroom/cask was moved. Tap homebrew/cask-cask instead.
```
```$ brew install homebrew/cask/gtkwave```

以下のコマンドを実行し、gtkwaveがインストールされているか確認してください。
```$ open /Applications/```

#Hello, world!
開発環境が整いました。まずはHello wolrdで使い方を覚えましょう。
以降のプログラムや実行ファイルは、[こちら](https://www.dropbox.com/s/ml3uk8xyj2p20xr/logic_circuit.zip?dl=0)からダウンロードできます。  
Verilogは、コンパイルを行ってからシミュレータで実行します。
まずは、helloworld.vを作成してください。

```verilog:helloworld.v
module main ();
    initial $display("hello, world!");
endmodule
```
ターミナルからコンパイルと実行をします。コンパイルにはiverilog, 実行にはvvpを使用します。

```terminal
$ iverilog -o helloworld helloworld.v 
$ vvp helloworld
```
hello, world!と表示されれば成功です。

#論理ゲート
AND, OR, NOT, NAND, NOR, XOR, XNORの論理ゲートを実装します。それぞれ二つの入力から出力結果を見ていきます。gtkwaveの使い方はANDの項で説明します。

##AND
入力をa,bとし、出力をoutとします。
入力は、(a,b) = (0,0), (1,0), (0,1), (1,1), (0,0)の順で行われます。

```verilog:AND.v
module ANDTEST;
reg a,b;
wire out;

and(out, a, b);

initial begin
    $dumpfile("AND.vcd");
    $dumpvars(0, ANDTEST);

        a = 0; b = 0;
    #10 a = 1;
    #10 a = 0; b = 1;
    #10 a = 1;
    #10 a = 0; b = 0;
    #10 $finish;
end

endmodule 
```
コンパイルします。-o ANDで出力するファイルの名前を指定しています。

```terminal
$ iverilog -o AND AND.v
```
シミュレーションをします。vvpの後に半角スペースを挟んで-oで指定したファイル名を入力します。
実行するとAND.vcdが出力され、以下のように表示されます。

```terminal
$ vvp AND
VCD info: dumpfile AND.vcd opened for output.
```
AND.vcdはgtkwaveで開かれます。openコマンドでAND.vcdを開きましょう。

```terminal
$ open AND.vcd
```
開くと以下の画面が表示されると思います。
<img width="998" alt="tutorial.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/638117ea-0fcb-af12-c1a7-7fbfb6b168b0.png">

SSTにあるANDTESTをクリックし、下の枠に表示されるa,b,outを選択してAppendをクリックしましょう。
すると以下のように波形が表示されます。
<img width="1000" alt="AND.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/f1898a78-edaf-8585-a4e0-6e2180c5b3be.png">
真理値表と見比べてみましょう。
0~10secの時、入力は(a,b)=(0,0)なのでoutは0になっています。10~20secでは(1,0)なのでoutは0です。
ANDの論理ゲートなので、30~40secの区間の(1,1)のみoutが1になっています。

| a | b | out |
|:-:|:-:|:-:|
| 0 | 0 | 0 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 1 | 1 |

次項からは、コードとgtkwaveの結果と真理値表のみ書きますのでコンパイル等はこの項を参照して下さい。

##OR
```verilog:OR.v
module ORTEST;
reg a, b;
wire out;

or(out, a, b);

initial begin
    $dumpfile("OR.vcd");
    $dumpvars(0, ORTEST);

        a = 0; b = 0;
    #10 a = 1;
    #10 a = 0; b = 1;
    #10 a = 1;
    #10 a = 0; b = 0;
    #10 $finish;
end

endmodule
```
<img width="999" alt="OR.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/9ecb4f87-a129-4e9e-3acc-f57d86f638ab.png">

| a | b | out |
|:-:|:-:|:-:|
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 1 |

##NOT
```verilog:NOT.v
module NOTTEST;
reg a;
wire out;

not(out, a);

initial begin
    $dumpfile("NOT.vcd");
    $dumpvars(0, NOTTEST);
        a = 0;
    #10 a = 1;
    #10 $finish;
end

endmodule
```
<img width="1001" alt="NOT.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/57ecb38b-5e80-fe58-9cd2-9b04d379e83b.png">

| a | out |
|:-:|:-:|
| 0 | 1 |
| 1 | 0 |

##NAND

```verilog:NAND.v
module NANDTEST;
reg a, b;
wire out;

nand(out, a, b);

initial begin
    $dumpfile("NAND.vcd");
    $dumpvars(0, NANDTEST);

        a = 0; b = 0;
    #10 a = 1;
    #10 a = 0; b = 1;
    #10 a = 1;
    #10 a = 0; b = 0;
    #10 $finish;
end

endmodule
```
<img width="999" alt="NAND.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/3e122e03-d383-8189-b07a-32e9566d6362.png">

| a | b | out |
|:-:|:-:|:-:|
| 0 | 0 | 1 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 0 |

##NOR

```verilog:NOR.v
module NORTEST;
reg a, b;
wire out;

nor(out, a, b);

initial begin
    $dumpfile("NOR.vcd");
    $dumpvars(0, NORTEST);

        a = 0; b = 0;
    #10 a = 1;
    #10 a = 0; b = 1;
    #10 a = 1;
    #10 a = 0; b = 0;
    #10 $finish;
end

endmodule
```
<img width="1000" alt="NOR.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/231af041-1ff0-0150-29a1-e37bf0a6898a.png">

| a | b | out |
|:-:|:-:|:-:|
| 0 | 0 | 1 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 1 | 0 |

##XOR

```verilog:XOR.v
module XORTEST;
reg a, b;
wire out;

xor(out, a, b);

initial begin
    $dumpfile("XOR.vcd");
    $dumpvars(0, XORTEST);

        a = 0; b = 0;
    #10 a = 1;
    #10 a = 0; b = 1;
    #10 a = 1;
    #10 a = 0; b = 0;
    #10 $finish;
end

endmodule
```
<img width="1000" alt="XOR.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/df63fbb6-472d-220d-b75f-1f26a7adf15c.png">

| a | b | out |
|:-:|:-:|:-:|
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 0 |

##XNOR
```verilog:XNOR.v
module XNORTEST;
reg a, b;
wire out;

xnor(out, a, b);

initial begin
    $dumpfile("XNOR.vcd");
    $dumpvars(0, XNORTEST);

        a = 0; b = 0;
    #10 a = 1;
    #10 a = 0; b = 1;
    #10 a = 1;
    #10 a = 0; b = 0;
    #10 $finish;
end

endmodule
```
<img width="999" alt="XNOR.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/af2cce43-fb37-d850-9c25-5eb976594258.png">

| a | b | out |
|:-:|:-:|:-:|
| 0 | 0 | 1 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 1 | 1 |

#Half Adder
全ての論理ゲートの実装ができました。そんなに難しくはなかったと思います。
次は、半加算器(Half Adder)を実装していきましょう。まず、回路を確認します。
![HA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/ebce2050-c038-0eb3-92b6-b18d1a2b4392.png)
半加算器は、S =  xor(a, b), C = and(a, b)となっています。
それではVerilogを書いていきましょう。出力が1つ増えたのでsumとcarryとし、wireに2つ書きます。使われているゲートはANDとXORなのでそれぞれのゲートに通します。

```verilog:HalfAdder.v
module HalfAdder;
reg a, b;
wire carry, sum;

and(carry, a, b);
xor(sum, a, b);

initial begin
    $dumpfile("HalfAdder.vcd");
    $dumpvars(0, HalfAdder);

        a = 0; b = 0;
    #10 a = 1;
    #10 a = 0; b = 1;
    #10 a = 1;
    #10 a = 0; b = 0;
    #10 $finish;
end

endmodule
```

gtkwaveの結果真理値表と比較しましょう。
<img width="1000" alt="HA.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400994/401484e8-bf42-142a-ad51-62409ccce5aa.png">

| a | b | carry | sum |
|:-:|:-:|:-:|:-:|
| 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 1 |
| 0 | 1 | 0 | 1 |
| 1 | 1 | 1 | 0 |

#終わりに
今回Verilogを触れてみて面白いと思って頂けたら嬉しいです。
Verilogにはassignやalwaysなど、ある程度定められた構文があるので調べてみてください。
論理ゲートから半加算器まではなんとなくでできますが、全加算器の実装となるとVerilogの知識がさらに必要になってきます。私は分からなかったので、是非やってみてください。
HDLを使ってFPGAという集積回路にプログラムができるみたいです。知らないことばかりですね。  
最後に、参考にさせて頂いたサイトやツールを文献にまとめて以上とします。
ありがとうございました。

#参考にさせて頂いたサイトやツール
・【Verilog】MacでのVerilogHDLの環境構築とサンプルコード
[https://miyanetdev.com/archives/240](https://miyanetdev.com/archives/240)  
・論理回路エディタ
[https://www.belltree.tokyo/logic-circuit-editor/](https://www.belltree.tokyo/logic-circuit-editor/)

・新居良祐サポートページ - Verilog-HDL入門
[http://cas.eedept.kobe-u.ac.jp/~arai/Verilog/index.html](http://cas.eedept.kobe-u.ac.jp/~arai/Verilog/index.html)

・論理ゲート
[http://www.ee.t-kougei.ac.jp/tuushin/lecture/lcircuit/gate/index.html](http://www.ee.t-kougei.ac.jp/tuushin/lecture/lcircuit/gate/index.html)

・Verilog Reference Guide
[http://in.ncu.edu.tw/ncume_ee/digilogi/vhdl/Verilog_Reference_Guide.pdf](http://in.ncu.edu.tw/ncume_ee/digilogi/vhdl/Verilog_Reference_Guide.pdf)