Chisel入門書「Digital Design with Chisel」2章の勉強記録

# 記事の概要
Chiselの入門書「Digital Design with Chisel」の2章の勉強記録です。
本文の概要を備忘録として整理し、また実際に行った演習を紹介します。

本のpdfデータとプログラム一式は無料で以下から入手できます。
https://raw.githubusercontent.com/wiki/schoeberl/chisel-book/chisel-book.pdf
https://github.com/schoeberl/chisel-book

## 2.1 Signal Types and Constants

Chiselには３つのデータ型、Bits、UInt、SIntがあります。引数でビット幅を指定します。

```Scala
Bits(8.W)    // 8ビットデータ
UInt(8.W)    // 8ビット符号なし整数
SInt(10.W)   // 10ビット符号付き整数
```
これらの型を用いて、信号、組み合わせ論理回路、およびレジスタを記述できます。例えば、1章のサンプルでは、LED用の1ビット出力信号ledを以下のように記述していました。

```Scala
val led= Output(UInt(1. W))
```

定数データを記述する時は、引数なしのメソッド呼び出しを使います。

```Scala
0.U  // UIntの定数0 
-3.S // SIntの定数-3
```

メソッドの引数にビット幅を指定することもできます。

```Scala
8.U(4.W) // UIntの4-bit定数8
```

例えば、1章のサンプルでは、レジスタを32ビットの定数0で初期化する際、以下のように記述していました。

```Scala
val cntReg = RegInit(0.U(32.W))
```

ビット幅を省略しても、自動で幅を推測してくれるので、以下のようなビット幅なしでの記述が可能です。

```Scala
255.U           // UIntの定数255
"hff".U         // UIntの定数255の16進数表現
"o377".U        // UIntの定数255の8進数表現 
"b1111_1111".U  // UIntの定数255の2進数表現
```

.Uや.SはChiselのデータ型なので、これらのメソッド呼び出しはchisel3のパッケージを以下のようにimportしていないとエラーになります。

```Scala
import chisel 3._
```
Chiselでは論理値のBool型は以下のように定義します。

```Scala
Bool() 
true.B 
false.B
```

Chiselで論理値を使用する際は、Scalaのtrueやfalseを.Bのメソッド呼び出しでChiselのBool型に変換しないといけません。

## 2.2 Combinational Circuits

- 組み合わせ回路の記述例

```Scala
val logic = (a & b) | c
```

- 論理演算子一覧

```Scala
val and = a & b 
val or = a | b  
val xor = a ˆ b  
val not = ˜a 
```

- 算術演算子一覧

```Scala
val add = a + b // addition 
val sub = a - b // subtraction 
val neg = -a // negate 
val mul = a * b // multiplication 
val div = a / b // division 
val mod = a % b // modulo operation
```

- 信号のタイプを先に定義してから、:=更新演算子を使用して、信号に値を割り当てることもできます。

```Scala
val w = Wire(UInt())
w := a & b
```

- 1ビットの抽出

```Scala
val sign = x(31)
```

- ビットの抜き出し範囲の指定

```Scala
val lowByte = largeWord(7, 0)
```

- 信号の結合

```Scala
val word = Cat(highByte, lowByte)
```

### 2.2.1 Multiplexer
- 2：1マルチプレクサ

```Scala
val result = Mux(sel, a, b)
```

selは選択信号であり、ChiselのBool型です。
selがtrue.Bならば、信号yは信号aになります。
selがfalse.Bならば、信号yは信号bになります。

## 2.3 Registers
レジスタはD-フリップフロップの集合です。
Chiselではレジスタを記述すると、暗黙裡にクロックと接続されるので、わざわざクロックを記述する必要はありません。
クロックの立ち上がりでデータ更新されます。
（備忘録：ここまで読んで、立ち下がりエッジや両エッジでデータ更新したい場合は、どうすればいいのか疑問に思いました。）

- リセット時に0で初期化される8ビットレジスタの例

```Scala
val reg = RegInit(0.U(8.W))
```

- 入力信号は:=更新演算子によりレジスタに接続され、レジスタの出力は式の名前を使用します。

```Scala
reg := d 
val q = reg
```

qはリセット時には0で、クロックの立ち上がりごとに、1サイクル前のdの値を出力するフリップフロップになります。

- レジスタを定義する段階で入力信号と接続することもできます

```Scala
val nextReg = RegNext(d)
```

nextReg はクロックの立ち上がりごとに、1サイクル前のdの値を出力するフリップフロップになります。
この式では、リセット時には値が不定になります。


- レジスタを定義する段階で入力信号と接続し、初期値を与えることもできます

```Scala
val bothReg = RegNext(d, 0.U)
```

bothReg はリセット時には0で、クロックの立ち上がりごとに、1サイクル前のdの値を出力するフリップフロップになります。

### 2.3.1 Counting
- 1から10までを繰り返しカウントするカウンター

```Scala
val cntReg = RegInit(0.U(8.W))
cntReg := Mux(cntReg === 9.U, 0.U, cntReg + 1.U)
```

## 2.4 Structure with Bundle and Vec
異なるタイプの複数の信号をまとめるのにはBundleを用います。

```Scala
class Channel() extends Bundle { 
  val data = UInt(32.W) 
  val valid = Bool() 
}
```

Bundleのフィールド（定義した各信号のこと）を使用するには、newでBundle を作成し、Wireオブジェクトを使用します。

```Scala
val ch = Wire(new Channel()) 
```

C++言語においてクラスのメンバ変数を使用するのと同じように、フィールドにはドット表記でアクセスします。

```Scala
ch.data := 123.U 
ch.valid := true.B
```

バンドルはフィールドだけを参照できます。

```Scala
val b = ch.valid
```

また、全体を参照することもできます。

```Scala
val channel = ch
```

同じタイプの複数の信号をまとめるのにはVecを用います。
マルチプレクサーを作成する場合は、Wireオブジェクトを使用します。

```Scala
val v = Wire(Vec(3, UInt(4.W)))
```

個々の要素には（インデックス）を使用してアクセスします。

```Scala
v(0) := 1.U 
v(1) := 3.U 
v(2) := 5.U
```

レジスタの配列を作成する場合は、Regオブジェクトを使用します。
例えば、64ビット幅の32ビットのレジスタファイルは以下のようになります。

```Scala
val registerFile = Reg(Vec(32, UInt(64.W)))
```

レジスタファイルの要素には、インデックスを使用してアクセスし、通常のレジスタとして使用されます。

```Scala
registerFile(idx) := dIn 
val dOut = registerFile(idx)
```

VecにBundleを含めることもできます。

```Scala
val vecBundle = Wire(Vec(8, new Channel()))
```

BundleにVecを含めることもできます。

```Scala
class BundleVec extends Bundle { 
  val field = UInt(8.W) 
  val vector = Vec(4,UInt(8.W)) 
}
```

Bundleタイプのレジスタにリセットによる初期値が必要な場合は、まずBundleを作成し、個々のフィールドの初期値を設定してから、

```Scala
val initVal = Wire(new Channel())
initVal.data := 0.U 
initVal.valid := false.B
```
このBundleをRegInitに渡します。

```Scala
val channelReg = RegInit(initVal)
```

## 2.5 Chisel Generates Hardware
Chiselからハードウェアを作成する際の諸注意が述べられています。

## 2.6 Exercise
演習にはFPGAボードにArty S7を使用しました。vivadoでのFPGAボードの使用方法は[1章の記事](https://qiita.com/Kosuke_Matsui/items/80dde1219e3ce02c4b66)を参照ください。


### プロジェクトの作成
本では1章のプログラムを修正するように指示されていましたが、ここでは新規にプロジェクトを作成しました。

サンプルプロジェクトをコピーして、不要なファイルを削除します。

```
git clone https://github.com/ucb-bar/chisel-template.git Chap2
cd Chap2
rm -r src/main/scala/* src/test/scala/*
rm -rf .git 
git init 
git add .gitignore *
``` 

build.sbatのプロジェクト名を修正します。

```
name := "chisel-module-template" 
```
上記を以下に修正。

```
name := "Chap2" 
```

verilogに変換する際は、Chap2フォルダの階層にてsbtを起動し、runMainを実行します

```
sbt
```

```
sbt:Chap2> runMain Chap2
```



### 制約ファイル
今回の制約ファイルは以下になります。使用方法は、[1章の記事](https://qiita.com/Kosuke_Matsui/items/80dde1219e3ce02c4b66)を参照ください。

```
## This file is a general .xdc for the Arty S7-25 Rev. E
## To use it in a project:
## - uncomment the lines corresponding to used pins
## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project

## Clock Signals
set_property -dict { PACKAGE_PIN F14   IOSTANDARD LVCMOS33 } [get_ports { clock }]; #IO_L13P_T2_MRCC_15 Sch=uclk
create_clock -add -name sys_clk_pin -period 83.333 -waveform {0 41.667} [get_ports { clock }];

## Switches
set_property -dict { PACKAGE_PIN H14   IOSTANDARD LVCMOS33 } [get_ports { io_sw[0] }]; #IO_L20N_T3_A19_15 Sch=sw[0]
set_property -dict { PACKAGE_PIN H18   IOSTANDARD LVCMOS33 } [get_ports { io_sw[1] }]; #IO_L21P_T3_DQS_15 Sch=sw[1]
set_property -dict { PACKAGE_PIN G18   IOSTANDARD LVCMOS33 } [get_ports { io_sw[2] }]; #IO_L21N_T3_DQS_A18_15 Sch=sw[2]

## LEDs
set_property -dict { PACKAGE_PIN E18   IOSTANDARD LVCMOS33 } [get_ports { io_led }]; #IO_L16N_T2_A27_15 Sch=led[2]

## Buttons
set_property -dict { PACKAGE_PIN G15   IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L18N_T2_A23_15 Sch=btn[0]

## Configuration options, can be used for all designs
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property CFGBVS VCCO [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]

## SW3 is assigned to a pin M5 in the 1.35v bank. This pin can also be used as
## the VREF for BANK 34. To ensure that SW3 does not define the reference voltage
## and to be able to use this pin as an ordinary I/O the following property must
## be set to enable an internal VREF for BANK 34. Since a 1.35v supply is being
## used the internal reference is set to half that value (i.e. 0.675v). Note that
## this property must be set even if SW3 is not used in the design.
set_property INTERNAL_VREF 0.675 [get_iobanks 34]
```

### スイッチによるLEDのON/OFF
以下をFPGAに書き込むと、スイッチSW0のON/OFFに連動してLD2がON/OFFします。

```Scala
/*
 * This code is a minimal hardware described in Chisel.
 * 
 * Copyright: 2013, Technical University of Denmark, DTU Compute
 * Author: Martin Schoeberl (martin@jopdesign.com)
 * License: Simplified BSD License
 * 
 */

import chisel3._
import chisel3.Driver

class Chap2 extends Module {
  val io = IO(new Bundle {
    val sw = Input(UInt(3.W))
    val led = Output(UInt(1.W))
  })

  val blkReg = RegInit(0.U(1.W))

  blkReg := io.sw
  io.led := blkReg
}

/**
 * An object extending App to generate the Verilog code.
 */
object Chap2 extends App {
  chisel3.Driver.execute(Array[String](), () => new Chap2())
}
```

### 2つのスイッチによるAND機能の実装
以下をFPGAに書き込むと、スイッチSW0とSW1を両方ともONにした場合のみ、LD2が点灯します。

```Scala
/*
 * This code is a minimal hardware described in Chisel.
 * 
 * Copyright: 2013, Technical University of Denmark, DTU Compute
 * Author: Martin Schoeberl (martin@jopdesign.com)
 * License: Simplified BSD License
 * 
 */

import chisel3._
import chisel3.Driver

class Chap2 extends Module {
  val io = IO(new Bundle {
    val sw = Input(UInt(3.W))
    val led = Output(UInt(1.W))
  })

  val blkReg = RegInit(0.U(1.W))

  val and = io.sw(0) & io.sw(1)
  blkReg := and
  io.led := blkReg 
}

/**
 * An object extending App to generate the Verilog code.
 */
object Chap2 extends App {
  chisel3.Driver.execute(Array[String](), () => new Chap2())
}
```
### 3つのスイッチによる2：1マルチプレクサ
以下をFPGAに書き込むと、スイッチSW2をONにした場合、SW0のON/OFFに連動してLD2がON/OFFします。また、スイッチSW2をOFFにした場合、SW1のON/OFFに連動してLD2がON/OFFします。

```Scala
/*
 * This code is a minimal hardware described in Chisel.
 * 
 * Copyright: 2013, Technical University of Denmark, DTU Compute
 * Author: Martin Schoeberl (martin@jopdesign.com)
 * License: Simplified BSD License
 * 
 */

import chisel3._
import chisel3.Driver

class Chap2 extends Module {
  val io = IO(new Bundle {
    val sw = Input(UInt(3.W))
    val led = Output(UInt(1.W))
  })

  val blkReg = RegInit(0.U(1.W))

  val result = Mux(io.sw(2), io.sw(0), io.sw(1))
  blkReg := result 
  io.led := blkReg 
}

/**
 * An object extending App to generate the Verilog code.
 */
object Chap2 extends App {
  chisel3.Driver.execute(Array[String](), () => new Chap2())
}
```

## 参考
- 堀江 徹也 「プログラマのためのFPGAによるRISC-Vマイコンの作り方」
    - 新規にプロジェクトを作成する手順は以下の本を参照しました。
- [Chiselの文法 - 入門編〜その2：Scala/Chiselの基本的なデータ型〜](https://www.tech-diningyo.info/entry/2019/05/26/174741) 
    - データ型について詳細で分かりやすい説明がされています。 
- [Chiselの文法 - 入門編 〜その4：Chiselの演算子〜](https://www.tech-diningyo.info/entry/2019/06/01/161044) 
    - 演算子について詳細で分かりやすい説明がされています。 
- [Chiselの文法 - 入門編 〜その6：ChiselのVec〜](https://www.tech-diningyo.info/entry/2019/06/02/150053) 
    - Vecについて詳細で分かりやすい説明がされています。  
- [Chiselの文法 - 入門編 〜その7：ChiselのBundle〜](https://www.tech-diningyo.info/entry/2019/06/08/193545) 
    - Bundleについて詳細で分かりやすい説明がされています。 


## 関連記事

[Chisel入門書「Digital Design with Chisel」1章の勉強記録](https://qiita.com/Kosuke_Matsui/items/80dde1219e3ce02c4b66)
[Chisel入門書「Digital Design with Chisel」3章の勉強記録](https://qiita.com/Kosuke_Matsui/items/b82edca18089084350c0)
[Chisel入門書「Digital Design with Chisel」4章の勉強記録](https://qiita.com/Kosuke_Matsui/items/23800cf34fb435225ec9)
[Chisel入門書「Digital Design with Chisel」5章の勉強記録](https://qiita.com/Kosuke_Matsui/items/847665e371185f14e735)
[Chisel入門書「Digital Design with Chisel」6章の勉強記録](https://qiita.com/Kosuke_Matsui/items/dd526ae4d59f30d1f586)
[Chisel入門書「Digital Design with Chisel」7章の勉強記録](https://qiita.com/Kosuke_Matsui/items/53a9e61facbc1cc79025)
[Chisel入門書「Digital Design with Chisel」8章の勉強記録](https://qiita.com/Kosuke_Matsui/items/3ab4be6bdba6d94be10b)
[Chisel入門書「Digital Design with Chisel」9章の勉強記録](https://qiita.com/Kosuke_Matsui/items/4c11d32c799800680f5c)