LoginSignup
0

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-09-12

記事の概要

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を考えます。

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つの出力になります。

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を下位モジュールに持つトップモジュールを作成できます。

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 で演算の種類を選択します。

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コンストラクタを使用するには以下をインポートする必要があります。

import chisel3.util._

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

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つのモジュール、フェッチステージ、デコードステージ、実行ステージを作成したとします。

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ポート単位で一括して接続できます。

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ポートにバルク接続できます。

io <> execute.io

4.4 Lightweight Components with Functions

  • 加算器

関数adderを定義します。

def adder (x: UInt, y: UInt) = { 
  x + y 
}

この関数adderを呼び出すだけで2つの加算器を作成できます

val x = adder(a, b) 
// another adder 
val y = adder(c, d)
  • 信号遅延用レジスタ

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

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

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

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

val delOut = delay(delay(delIn))

参考

関連記事

Chisel入門書「Digital Design with Chisel」1章の勉強記録
Chisel入門書「Digital Design with Chisel」2章の勉強記録
Chisel入門書「Digital Design with Chisel」3章の勉強記録
Chisel入門書「Digital Design with Chisel」5章の勉強記録
Chisel入門書「Digital Design with Chisel」6章の勉強記録
Chisel入門書「Digital Design with Chisel」7章の勉強記録
Chisel入門書「Digital Design with Chisel」8章の勉強記録
Chisel入門書「Digital Design with Chisel」9章の勉強記録

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0