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

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

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

## 4.1 Components in Chisel are Module
モジュールの階層構造を作成する方法について説明しています。
各モジュールのインターフェースの入出力ポートはbundleによってval ioにまとめられています。

まず、入力aとb、出力xとyを持つコンポーネントA、
入力in1、in2、出力outを持つコンポーネントBを考えます。

```Scala
class CompA extends Module { 
  val io = IO(new Bundle { 
    val a = Input(UInt(8.W)) 
    val b = Input(UInt(8.W)) 
    val x = Output(UInt(8.W)) 
    val y = Output(UInt(8.W))
  })
  
// function of A
}

class CompB extends Module { 
  val io = IO(new Bundle { 
    val in1 = Input(UInt(8.W)) 
    val in2 = Input(UInt(8.W)) 
    val out = Output(UInt(8.W)) 
  })
  
  // function of B
}
```

コンポーネントCをp30の図4.1のようなコンポーネントAとコンポーネントBを下位モジュールに持つモジュールとします。
インターフェースは3つの入力と2つの出力になります。

```Scala
class CompC extends Module { 
  val io = IO(new Bundle { 
    val in_a = Input(UInt(8.W)) 
    val in_b = Input(UInt(8.W)) 
    val in_c = Input(UInt(8.W)) 
    val out_x = Output(UInt(8.W)) 
    val out_y = Output(UInt(8.W)) 
  })
  
  // create components A and B 
  val compA = Module(new CompA()) 
  val compB = Module(new CompB())
  
  // connect A 
  compA.io.a := io.in_a 
  compA.io.b := io.in_b 
  io.out_x := compA.io.x 
  // connect B 
  compB.io.in1 := compA.io.y 
  compB.io.in2 := io.in_c 
  io.out_y := compB.io.out
}
```

下位モジュールの呼び出しにはModuleオブジェクトを用います。
val compA = Module(new CompA()) のように参照したcompAのフィールドとして各ポートにアクセスします。

同様にしてコンポーネントCとコンポーネントDを下位モジュールに持つトップモジュールを作成できます。

```Scala
class CompD extends Module { 
  val io = IO(new Bundle { 
    val in = Input(UInt(8.W)) 
    val out = Output(UInt(8.W)) 
  })
  
  // function of D
}

class TopLevel extends Module { 
  val io = IO(new Bundle { 
    val in_a = Input(UInt(8.W)) 
    val in_b = Input(UInt(8.W)) 
    val in_c = Input(UInt(8.W)) 
    val out_m = Output(UInt(8.W)) 
    val out_n = Output(UInt(8.W)) 
  })
  
  // create C and D 
  val c = Module(new CompC()) 
  val d = Module(new CompD())

  // connect C 
  c.io.in_a := io.in_a 
  c.io.in_b := io.in_b 
  c.io.in_c := io.in_c 
  io.out_m := c.io.out_x 
  
  // connect D 
  d.io.in := c.io.out_y 
  io.out_n := d.io.out
}
```

## 4.2 An Arithmetic Logic Unit
算術演算モジュールALUを作成します。
fn で演算の種類を選択します。

```Scala
class Alu extends Module { 
  val io = IO(new Bundle { 
    val a = Input(UInt(16.W)) 
    val b = Input(UInt(16.W)) 
    val fn = Input(UInt(2.W)) 
    val y = Output(UInt(16.W)) })
    
  // some default value is needed 
  io.y := 0.U
  
  // The ALU selection 
  switch(io.fn) {
    is(0.U) { io.y := io.a + io.b } 
    is(1.U) { io.y := io.a - io.b } 
    is(2.U) { io.y := io.a | io.b } 
    is(3.U) { io.y := io.a & io.b }
  }
}
```

Chiselのswitch/isコンストラクタを使用するには以下をインポートする必要があります。

```Scala
import chisel3.util._
```

ここでALUについて３章と同様にテストを行ってみます。
src/main/scalaに上記のALUソースコードを置き、src/test/scalaに以下を置いた上で、build.sbtのファイルのある階層でsbt runを実行します。

```Scala:aluScalaTest.scala
import chisel3._
import chisel3.iotesters._
import org.scalatest._

class TesterAlu(dut: Alu) extends PeekPokeTester(dut) {

  poke(dut.io.fn, 0.U)
  poke(dut.io.a, 3.U)
  poke(dut.io.b, 1.U)
  step(1)
  expect(dut.io.y, 4)
  poke(dut.io.fn, 1.U)
  poke(dut.io.a, 3.U)
  poke(dut.io.b, 1.U)
  step(1)
  expect(dut.io.y, 2)
  poke(dut.io.fn, 2.U)
  poke(dut.io.a, 5.U)
  poke(dut.io.b, 3.U)
  step(1)
  expect(dut.io.y, 7)
  poke(dut.io.fn, 3.U)
  poke(dut.io.a, 3.U)
  poke(dut.io.b, 5.U)
  step(1)
  expect(dut.io.y, 1)
}

class AluSpec extends FlatSpec with Matchers {

  "Tester" should "pass" in {
    chisel3.iotesters.Driver(() => new Alu()) {
      c => new TesterAlu(c)
    } should be (true)
  }
}
```

以下の結果がコンソールに表示されます。

```
[info] AluSpec:
[info] Tester
[info] - should pass
[info] ScalaTest
[info] Run completed in 3 seconds, 450 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
```



## 4.3 Bulk Connections
Chiselは、複数のIOポートを持つコンポーネント同士を簡単に接続できるように、バルク接続演算子<>を提供しています。

例えば、CPUをパイプライン化するために、3つのモジュール、フェッチステージ、デコードステージ、実行ステージを作成したとします。

```Scala
class Fetch extends Module { 
  val io = IO(new Bundle { 
    val instr = Output(UInt(32.W)) 
    val pc = Output(UInt(32.W)) 
  }) 
  // ... Implementation of fetch 
}

class Decode extends Module { 
  val io = IO(new Bundle { 
    val instr = Input(UInt(32.W)) 
    val pc = Input(UInt(32.W)) 
    val aluOp = Output(UInt(5.W)) 
    val regA = Output(UInt(32.W)) 
    val regB = Output(UInt(32.W)) 
  }) 
  // ... Implementation of decode 
}

class Execute extends Module { 
  val io = IO(new Bundle { 
    val aluOp = Input(UInt(5.W)) 
    val regA = Input(UInt(32.W)) 
    val regB = Input(UInt(32.W)) 
    val result = Output(UInt(32.W)) 
  }) 
  
  // ... Implementation of execute 
}

```

この3つのステージを4.1のように:=でつないでいくのではなく、以下のようにioポート単位で一括して接続できます。

```Scala
val fetch = Module(new Fetch()) 
val decode = Module(new Decode()) 
val execute = Module(new Execute)

fetch.io <> decode.io 
decode.io <> execute.io 
```

バルク接続により同じ名前を持つIOポートは接続され、一致する名前のないIOポートには何も接続されません。

同じ階層のIOポート同士だけではなく、サブモジュールのIOポートを親モジュールのIOポートにバルク接続できます。

```Scala
io <> execute.io
```

## 4.4 Lightweight Components with Functions
- 加算器

関数adderを定義します。

```Scala
def adder (x: UInt, y: UInt) = { 
  x + y 
}
```
この関数adderを呼び出すだけで2つの加算器を作成できます

```Scala
val x = adder(a, b) 
// another adder 
val y = adder(c, d)
```

- 信号遅延用レジスタ

関数の定義にはレジスタを使用することができます。

```Scala
def delay(x: UInt) = RegNext(x)
```

この関数は信号を1クロックサイクル遅延させます。

この関数自体をパラメーターとして呼び出すことにより、2クロックサイクルを遅延させることができます。

```Scala
val delOut = delay(delay(delIn))
```

## 参考
- [Chiselの文法 - 入門編〜その１:モジュールの定義とエラボレート〜](https://www.tech-diningyo.info/entry/2019/05/26/134950)
    - モジュールの定義について詳細で分かりやすい説明がされています。

## 関連記事

[Chisel入門書「Digital Design with Chisel」1章の勉強記録](https://qiita.com/Kosuke_Matsui/items/80dde1219e3ce02c4b66)
[Chisel入門書「Digital Design with Chisel」2章の勉強記録](https://qiita.com/Kosuke_Matsui/items/be68930d121b13402e2a)
[Chisel入門書「Digital Design with Chisel」3章の勉強記録](https://qiita.com/Kosuke_Matsui/items/b82edca18089084350c0)
[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)