Verilog wireとregの使い分け

# はじめに
FPGAの授業の補助資料として入門したての頃に詰まったポイント、早く知っていればよかったなというポイントをいくつかまとめて記事にします。
今回はVerilogを書き始めたときに詰まったwireとregの使い分けです。

# wireとreg
Verilogのデータ型として主に用いるのはwire(ネット型)とreg(レジスタ型)です。

wireは配線に対応し組み合わせ回路の記述に使えますが、regは記述の仕方によって組み合わせ回路になったり順序回路であるFFやラッチになったりします。

文法的には

* wire: assign文でのみ代入可能
* reg: always文やfunction文などで代入可能

という違いがあります。

個人的ですが、使い分けとしては

1. 順序回路を作りたいとき  
  **reg**を使い**always文**で記述
2. 単純な組み合わせ回路を作りたいとき  
  **wire**を使い**assign文**で記述
3. 複雑な組み合わせ回路のうち、入力が異なるだけでロジックが同じものを複数作りたい時  
  **wire**を使い回路は**function文**で記述（もしくは**4+module化**)
4. 複雑な組み合わせ回路のうち、再利用が考えられないもの  
  **reg**を使い**always文**で記述

なお、3の場合で出力が複数ある場合は別のモジュールにして記述すると良いと思います。

# 例
以下いくつか回路記述例と合成後の実際の回路を示します。
##  1. 順序回路(フリップフロップやラッチ)を作りたいとき 
### フリップフロップの例
例えばクロックをCLK、入力をA、出力をQとして、クロック立ち上がり時にAが1の時、Qが反転するという順序回路は

```verilog
module ex1(
    input wire CLK,
    input wire RST,
    input wire A,
    output reg Q
    );
    always @(posedge CLK) begin
        if(RST) Q <= 1'd0;
        else if(A)  Q <= !Q;
    end
endmodule
```
とかくと
![image.png](https://qiita-image-store.s3.amazonaws.com/0/140084/726cfabb-ba13-0096-df68-a074cb465ac4.png)

のようにFFが生成されます。
always文でクロックに同期して出力の値が変わるようにイベント式に`@(posedge CLK)`などと記述するとFFが生成されます。

### ラッチの例

ラッチを生成したい場合はイベント式に出力を変化させるのに必要な信号線をすべて列挙し`@(A or Q or RST)`などと書くと
![image.png](https://qiita-image-store.s3.amazonaws.com/0/140084/d324f8df-4998-57f2-c823-41ff9dafe1ca.png)
のようにラッチが生成されます。

> なお、always文で組み合わせ回路やラッチを作成する場合、出力に必要な信号線をすべて列挙する書き方をすると漏れがある可能性があるため`@(*)`という省略記法で記述することをおすすめします。

## 2. 単純な組み合わせ回路を作りたいとき 
### 組み合わせ回路 assign文の例
入力A,Bの論理積を取ったものを出力Cとするとき

```verilog
module ex2_1(
    input wire A,
    input wire B,
    output wire C
    );
    assign C = A & B;
endmodule
```
とかくと
![image.png](https://qiita-image-store.s3.amazonaws.com/0/140084/db75abf7-ae71-160a-0349-b26b6d267827.png)
のような回路が生成されます。

### 組み合わせ回路 assign文+三項演算子の例
> また、好みですがwire+always+if-elseによる組み合わせ回路の代わりに三項演算子を使って条件分岐させて出力を決める組み合わせ回路もassignで記述できます。(同様の記述のalways版は[こちら](#組み合わせ回路-always文の例)をご覧ください)
入力をA, B出力をC(2ビット)とし、Aが1なら0b11を、Aが0でBが1なら0b01を、そうでないなら0b00を出力するものは

> ```verilog
module ex2_2(
    input wire A,
    input wire B,
    output wire[1:0] C
    );
    assign C =  A ? 2'b11 :
                B ? 2'b01 :
                2'b00;
endmodule
```
> ![image.png](https://qiita-image-store.s3.amazonaws.com/0/140084/370cfaff-c849-bd54-bcbf-9c31f1b75b93.png)
> という回路が生成されます。

## 3.複雑な組み合わせ回路のうち、入力が異なるだけでロジックが同じものを複数作りたい時  
複数の信号に対して同じ組み合わせ回路を使う場合はfunction文を使うかmodule化しておくとコードが短くなりメンテナンスがしやすいです。（コピペをするとあとでバグが見つかったときに修正漏れが生じて悪化します)

### 組み合わせ回路 function文の例
ここではR,G,B 8bit入力に対して組み合わせ回路で4値化し、4値化結果をくっつけて出力O(6bit)とします。

4値化の基準は以下のとおりです

|入力|出力|
|:--:|:-:|
|8'd0|2'b00|
|8'd1~8'd63|2'b01|
|8'd64~8'd127|2'b10|
|8'd128~8'd255|2'b11|

```verilog
module ex3(
    input [7:0] R,
    input [7:0] G,
    input [7:0] B,
    output [5:0] O
    );
    function [1:0] convert(input [7:0] p);
    begin
        if(p == 8'd0) convert = 2'b00;
        else if(p <= 8'd63) convert = 2'b01;
        else if(p <= 8'd127) convert = 2'b10;
        else convert = 2'b11;
    end
    endfunction
    wire [1:0] r_4 = convert(R);
    wire [1:0] g_4 = convert(G);
    wire [1:0] b_4 = convert(B);
    assign O = {r_4, g_4, b_4};
endmodule
```
生成さた回路を見てみると下図のように各色ごとに同じような回路が生成されていることがわかります。
![bitmap.png](https://qiita-image-store.s3.amazonaws.com/0/140084/39b739ff-f4b1-d221-18dc-8aeb2b38c357.png)

## 4. 複雑な組み合わせ回路のうち、再利用が考えられないもの 
複雑な組み合わせ回路のうち1箇所でしか使わない、もしくは複数箇所で使われるがモジュール化する場合は好みですが、個人的にはalways＋regで書く事が多いです。

### 組み合わせ回路 always文の例
[2で示した回路](#組み合わせ回路-assign文の例)と同様のものをalways文で記述してみます。

```verilog
module ex4_1(
    input wire A,
    input wire B,
    output reg [1:0] C
    );
    always @(*) begin
        if (A) C <= 2'b11;
        else if(B) C <= 2'b01;
        else C <= 2'b00;
    end
endmodule
```
この方法で組み合わせ回路を記述する際は

* イベント式に内部で使うものすべてを列挙するか*を使う
* すべての条件でregに代入する(regの値を代入しない条件が生じる場合、値を保持する必要があると判定されてラッチが生成されます。)

の2点に注意してください。

生成された回路は以下のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/140084/2e12b13a-12c6-194f-f878-c114fc9d1cca.png)

[2で示した回路](#組み合わせ回路-assign文の例)より最適化されたものが生成されました。

### 組み合わせ回路 always文+module化したものを利用する例
[3で示した回路](#組み合わせ回路-function文の例)の4値化部分をconvertモジュールにし、モジュールを利用する例を次に示します。

```verilog
module convert(
    input [7:0] p,
    output reg [1:0]  o
);
    always @(*) begin
        if(p == 8'd0) o <= 2'b00;
        else if(p <= 8'd63) o <= 2'b01;
        else if(p <= 8'd127) o <= 2'b10;
        else o <= 2'b11;
    end
endmodule

module ex4_2(
    input [7:0] R,
    input [7:0] G,
    input [7:0] B,
    output [5:0] O
    );
   
    wire [1:0] r_4;
    wire [1:0] g_4;
    wire [1:0] b_4;
    convert r_c(R, r_4);
    convert g_c(G, g_4);
    convert b_c(B, b_4);
    assign O = {r_4, g_4, b_4};
endmodule
```
のように上位モジュールでconvertモジュールを複数記述してあげて利用することも出来ます。
この場合も[3で示した回路](#組み合わせ回路-function文の例)と同じような回路が生成されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/140084/47561e24-545c-04c5-68de-03bf6660dd46.png)
![bitmap.png](https://qiita-image-store.s3.amazonaws.com/0/140084/56f5165f-5e9c-bfaf-da1b-b5d2f89479cb.png)