Verilog HDLによる順序回路の設計(授業用)

クロックなどの信号によって状態が変化する順序回路は、always文を用いて設計する。always文では指定した信号に変化(立上り、立下り)があった時に行う処理を記述する。

# レジスタの設計

## 実習1. 4ビットレジスタの設計
以下の register4.v で設計される回路を実習ボードに実装して、動作を確かめること。
ただし top-level entity は register4 とする。
入出力の割り当ては表の通りにすること。

```Verilog:register4.v
`default_nettype none

module register4(
  input   wire        clock,
  input   wire  [3:0] data,
  output  reg   [3:0] q
  );
  
  always @ (posedge clock) begin // センシティビティリスト
                                 // clock の立上りのタイミングでalways文が起動
    q <= data;  // ノンブロッキング代入
  end
  
endmodule
```


|register4のポート| I/O デバイス |備考|
|:---:|:---:|:---|
|clock| GCLK3 (プッシュスイッチ)|ジャンパピンJP10を右側に設置して利用する。ボタン押下げ時に1|
|data[3:0]| SA3~SA0(トグルスイッチ)| |
|q[3:0] | DA3~DA0(個別LED) | |

回路の動作例
![timing-chart-register.png](https://qiita-image-store.s3.amazonaws.com/0/25656/b4bae94e-2184-f1b8-14d5-83df2aee9734.png)

設計する回路のイメージ
![register4.png](https://qiita-image-store.s3.amazonaws.com/0/25656/2d570435-c7e1-2f97-ba65-3b3890e6b688.png)

###　解説
always文では、センシティビティリスト(``always @`` に続く``()``内)に起動のタイミングを記述し、その起動のタイミングで実行される処理を引き続く文(通常は``begin~end``で囲まれる複文)で記述する。

```
always @ (<センシティビティリスト>)
 <センシティビティリストの信号に変化があった時に実行される文>;
 // 複数の処理を行いたい場合(複文)はbegin ~ endで囲む 
```
- センシティビティリストに指定された信号に変化があったタイミングでalways文が起動し処理が実行される
 - センシティビティリストでは、``posedge``で立上り、``negedge``で立下りを指定する
 - 実習1ではセンシティビティリストに`` posedge clock ``と記述することで、clockの立上りのタイミングで処理を行うことを指定している
- クロックなどの信号の変化のタイミングでレジスタに値を代入するような処理を行いたい場合は、alwaysで起動される文において、レジスタ型(reg型)変数へノンブロッキング代入``<=``で値を代入するように記述するとよい
 - 実習1では、clockの立上りのタイミングで、4ビットのreg型変数``q``に4ビットの信号``data``を代入し、その後、代入された信号を保持する回路を記述している(動作例を参照)


## 実習2. 同期式リセット付きレジスタの設計

以下の register4_sync_reset.v で設計される回路を実習ボードに実装して、動作を確かめること。
ただし top-level entity は register4_sync_reset とする。
入出力の割り当ては表の通りにすること。

```Verilog:regiger4_sync_reset.v
`default_nettype none

module register4_sync_reset(
  input   wire        clock,
  input   wire        n_reset,  // リセット(active low)
  input   wire  [3:0] data,
  output  reg   [3:0] q
  );
  
  always @ (posedge clock) begin
    // clockの立上りでalways文が起動
    if (n_reset == 1'b0) begin 
      q <= 4'b0; // n_resetがアクティブならリセット
    end else begin
      q <= data;
    end
  end
  
endmodule
```

|register4_sync_resetのポート| I/O デバイス |備考|
|:---:|:---:|:---|
|clock| GCLK3 (プッシュスイッチ)|ジャンパピンJP10を右側に設置して利用する。ボタン押下げ時に1|
|n_reset| S1 (プッシュスイッチ)| ボタン押下げ時に0(GND)|
|data[3:0]| SA3~SA0(トグルスイッチ)| |
|q[3:0] | DA3~DA0(個別LED) | |

回路の動作例
![timing-chart_register_sync_reset.png](https://qiita-image-store.s3.amazonaws.com/0/25656/cdbd0474-525b-97b3-51e1-8b82730630b7.png)

### 解説
alwaysで起動する文では if文やcase文を記述することができる

- 実習2では ``clock`` の立上りのタイミングで``n_reset``の値を判定し、その判定結果で異なる動作を行うような回路を記述している 

## 実習3. 非同期式リセット付きレジスタの設計

以下の register4_async_reset.v で設計される回路を実習ボードに実装して、動作を確かめること。
ただし top-level entity は register4_async_reset とする。
入出力の割り当ては表の通りにすること。

```Verilog:register4_async_reset.v
`default_nettype none

module register4_async_reset(
  input   wire        clock,
  input   wire        n_reset,  // リセット(active low)
  input   wire  [3:0] data,
  output  reg   [3:0] q
  );
  
  always @ (posedge clock, negedge n_reset) begin
    // clockの立上り、またはn_resetの立下りのタイミングでalways文が起動
    if (n_reset == 1'b0) begin
      q <= 4'b0; // n_resetがアクティブならリセット
    end else begin
      q <= data;
    end
  end
  
endmodule
```
|register4_async_resetのポート| I/O デバイス |備考|
|:---:|:---:|:---|
|clock| GCLK3 (プッシュスイッチ)|ジャンパピンJP10を右側に設置して利用する。ボタン押下げ時に1|
|n_reset| S1 (プッシュスイッチ)| ボタン押下げ時に0(GND)|
|data[3:0]| SA3~SA0(トグルスイッチ)| |
|q[3:0] | DA3~DA0(個別LED) | |

回路の動作例
![timing-chart_register_async_reset.png](https://qiita-image-store.s3.amazonaws.com/0/25656/883b21a5-d0bf-5972-c56c-f3e46af2a547.png)

### 解説
センシティビティリストには複数の信号を指定することができる

- 実習3では、センシティビティリストに ``posedge clock, negedge n_reset`` を指定することで、``clock``の立上りと``n_reset``の立下りの両方のタイミングで起動する回路を記述している
 
# カウンタの設計

## 実習4. 5進カウンタの設計

以下の counter5.v で設計される回路を実習ボードに実装して、動作を確かめること。
ただし top-level entity は counter5 とする。
入出力の割り当ては表の通りにすること。

```Verilog:counter5.v
`default_nettype none

module counter5(
  input   wire        clock,
  output  reg   [2:0] count
  );
  
  always @ (posedge clock) begin
    if (count >= 3'b100) begin
      count <= 3'b000;
    end else begin
      count <= count + 1'b1;
    end
  end
  
endmodule
```

|counter5のポート| I/O デバイス |
|:---:|:---:|
|clock| GCLK3 (プッシュスイッチ)|
|count[2:0] | DA2~DA0(個別LED) |


## 実習5. デコーダ付き5進カウンタの設計 (モジュール設計)

以下の counter5_decoder.v, register3.v, mod5_inc.v, decoder.v で設計される回路を実習ボードに実装して、動作を確かめること。
ただし top-level entity は counter5_decoder とする。
入出力の割り当ては表の通りにすること。

```Verilog:counter5_decoder.v
module counter5_decoder(
  input   wire        clock,
  output  wire  [7:0] y
  );

  wire  [2:0] count;       // 現在のカウント値
  wire  [2:0] count_next;  // 次のカウント値
  
  register3 register(  // 現在のカウント値を保持する3ビットレジスタ
    .clock  (clock),
    .data   (count_next),
    .q      (count)
  );
    
  mod5_inc mod5_inc(  // 現在のカウント値から次のカウント値を求める次状態関数 y = x + 1 mod 5
    .x      (count),
    .y      (count_next)
  );
  
  decoder decoder(  // 現在のカウント値をデコードして出力する出力関数
    .num    (count),
    .y      (y)
  );
  
endmodule
```

```Verilog:register3.v
`default_nettype none

module register3( // 3ビットレジスタ
  input   wire        clock,
  input   wire  [2:0] data,
  output  reg   [2:0] q
  );
  
  always @ (posedge clock) begin
    q <= data;
  end

endmodule
```

```Verilog:mod5_inc.v
`default_nettype none

module mod5_inc( // 5進カウント用の次状態関数(組合せ論理回路)
  input   wire  [2:0] x,
  output  reg   [2:0] y
  );
  
  always @ (*) begin
    if (x >= 3'b100) begin
      y = 3'b000;
    end else begin
      y = x + 1'b1;
    end  
  end
  
endmodule
```

```Verilog:decoder.v
`default_nettype none

module decoder( // 出力関数(組合せ論理回路)
  input   wire  [2:0] num,
  output  reg   [7:0] y
  );
  
  always @ (*) begin
    case (num)
      3'b000: y = 8'b11111110;
      3'b001: y = 8'b11111101;
      3'b010: y = 8'b11111011;
      3'b011: y = 8'b11110111;
      3'b100: y = 8'b11101111;
      3'b101: y = 8'b11011111;
      3'b110: y = 8'b10111111;
      3'b111: y = 8'b01111111;
    endcase
  end
  
endmodule
```
|counter5_decoderのポート| I/O デバイス |
|:---:|:---:|
|clock| GCLK3 (プッシュスイッチ)|
|y[7:0] | DA7~DA0(個別LED) |

回路のモジュール構成
![counter5_decoder.png](https://qiita-image-store.s3.amazonaws.com/0/25656/b2d15d54-df06-bfce-d2f1-be153d474b0f.png)

### 解説
順序回路を設計する際は、現在の状態を保持する記憶部(レジスタ)、現在の状態と入力信号から次の状態を算出する次状態関数回路(組合せ論理回路)、現在の状態(および入力信号)から出力信号を算出する出力関数回路(組合せ論理回路)のそれぞれをモジュールとして設計し、それらを組み合わせて構築するとよい。

課題5における記憶部、次状態関数回路、出力関数回路は以下に示されるモジュールで設計されている。
- 記憶部: register3モジュール
- 次状態関数回路(組合せ論理回路): mod5_incモジュール
- 出力関数回路(組合せ論理回路): decoderモジュール

# 状態マシンの設計

## 実習6. 一時停止機能付きグレイコードカウンタの設計

以下の gray_counter.v, next_state_function.v, register2.v で設計される回路を実習ボードに実装して、動作を確かめること。
ただし top-level entity は gray_counter とする。
入出力の割り当ては表の通りにすること。

```Verilog:gray_counter.v
`default_nettype none

module gray_counter(
  input   wire        clock,
  input   wire        pause,
  output  wire  [1:0] y
  );
  
  wire  [1:0] state_now;  // 現在の状態
  wire  [1:0] state_next; // 次の状態
  
  // 次状態関数
  next_state_function next_state_function(
    .pause      (pause),
    .state_now  (state_now),
    .state_next (state_next));
  
  // 記憶部 (2-bit register)
  register2 register2(
    .clock  (clock),
    .data   (state_next),
    .q      (state_now));
  
  // 出力関数
  assign y = state_now;
  
endmodule
```

```Verilog:next_state_function.v
`default_nettype none

// 次状態関数: 現在の状態と入力から次の状態を出力する組合せ論理回路
module next_state_function(
  input   wire        pause,
  input   wire  [1:0] state_now,
  output  reg   [1:0] state_next
  );
  
  // module 内でのパラメータ定義(各状態のビット表現の定義)
  localparam Sa = 2'b00;
  localparam Sb = 2'b01;
  localparam Sc = 2'b11;
  localparam Sd = 2'b10;
  
  always @ (*) begin
    case ({pause, state_now}) // 状態遷移表を記述する
      {1'b0, Sa}: state_next = Sb;
      {1'b0, Sb}: state_next = Sc;
      {1'b0, Sc}: state_next = Sd;
      {1'b0, Sd}: state_next = Sa;
      {1'b1, Sa}: state_next = Sa;
      {1'b1, Sb}: state_next = Sb;
      {1'b1, Sc}: state_next = Sc;
      {1'b1, Sd}: state_next = Sd;
    endcase
  end
  
endmodule
```

```Verilog:register2.v
`default_nettype none

// 2-bit レジスタ: 現在の状態を保持する
module register2 (
  input   wire        clock,
  input   wire  [1:0] data,
  output  reg   [1:0] q
  );

  always @ (posedge clock) begin
    q <= data;
  end
  
endmodule
```
|gray_counterのポート| I/O デバイス |
|:---:|:---:|
|clock| GCLK3(プッシュスイッチ) |
|pause| SA0(トグルスイッチ) |
|y[1:0] | DA1~DA0(個別LED) |

回路の状態遷移図
![gray_counter_state_machine_diagram.png](https://qiita-image-store.s3.amazonaws.com/0/25656/5262c44d-1c75-461d-baff-a59b1eb11794.png)

回路の動作例
![timing-chart-gray_code.png](https://qiita-image-store.s3.amazonaws.com/0/25656/382aa875-4219-2f76-bae2-883d68b25f8d.png)

回路のモジュール構成
![gray_counter.png](https://qiita-image-store.s3.amazonaws.com/0/25656/9333a9a6-6427-9583-597e-7602f4c89625.png)

### 解説

課題6における記憶部、次状態関数回路以下に示されるモジュールで設計されている。

- 記憶部: register2モジュール
- 次状態関数回路(組合せ論理回路): next_state_functionモジュール

出力関数については、今回、各状態を表す2ビットのビット表現を出力信号と同じになるようにしたため、特にモジュールとしては設計を行っていない。あえて言えば、gray_counterモジュール内の`` assign y = state_now;``の記述が出力関数に相当する。