はじめに
筆者は失恋でめんたるぼろぼろなので、間違いなどがありましたら優しく教えてくださいまし
すからは嫌になってきた
Chiselのビルド方法
Chiselをビルドするにはpart1で環境を整えたsbt(Simple Build Tool)
コマンドというものを使用していきます
Chiselまわりのライブラリをインターネットから引っ張ってきてビルドを自動的にやってくれるもの
ビルドに失敗したときは、インターネットの接続状態とハードウェアのデザインを見直す必要がある
ChiselやScalaのバージョンをいじりたいときはbuild.sbt(Chiselプロジェクトの一番親ディレクトリに書き込む設定ファイル)をカスタマイズすることで可能
全然シンプルじゃないけどこれの使い方をいかに記していきたいと思います
sbtのあれこれ
完全に余談ではあるが、sbtコマンドはMavenというビルドツールを派生させたものらしく、Java -> Maven -> sbt と作られていったのだそう
より深く知りたかったらMavenってやつを知る必要あり?(自分はめんどくさがりなのでパス)
プロジェクトの構造は以下のようになっているのがベース
.
├── build.sbt
├── project
│ ├── build.properties
│ ├── plugins.sbt
│ ├── project
│ │ └── target
│ └── target
├── src
│ ├── main
│ │ ├── java
│ │ ├── resources
│ │ ├── scala
│ └── test
│ ├── java
│ ├── resources
│ ├── scala
└── target
Chiselを用いたライブラリの作成
自作のクラスの作成の記述方法は以下のようになります
// ライブラリ名の定義
package mypack
// chiselのクラス一覧を全てインポート
import chisel3._
// オリジナルのクラスの定義
class ABC extends Modules{
val io = IO(new Bundle{})
}
import mypack._
// ABCクラス単体でのインポート方法
// import mypack.ABC
class ABCUser extends Module{
val io = IO(new Bundle{})
// オリジナルクラスの呼び出し
val abc = Module(new ABC())
}
うん、Javaと変わんない
Chiselでのテストベンチ記述方法
言うまでもないですが、ハードウェアのファイルに入力を与えて結果と予想を照らし合わせるためのファイルをテストベンチといいます
ChiselではテストベンチをPeekPokeTesterというもので値をぶっこんでいきます(なんか名前かわいい)
実際にテストベンチを以下のように作っていきます
書き方1つめ
import chisel3._
import chisel3.iotesters._
class DeviceUnderTest extends Module {
val io = IO(new Bundle {
val a = Input(UInt (2.W))
val b = Input(UInt (2.W))
val out = Output(UInt (2.W))
})
io.out := io.a & io.b
}
object Test extends App {
iotesters.Driver.execute(args, () => new DeviceUnderTest){
c => new PeekPokeTester(c) {
poke(dut.io.a, 0.U)
poke(dut.io.b, 1.U)
step (1)
println("Result is: " + peek(dut.io.out).toString)
poke(dut.io.a, 3.U)
poke(dut.io.b, 2.U)
step (1)
println("Result is: " + peek(dut.io.out).toString)
}
}
}
書き方2つめ
object Test extends App {
iotesters.Driver.execute(args, () => new DeviceUnderTest){
c => new PeekPokeTester(c) {
poke(dut.io.a, 3.U)
poke(dut.io.b, 1.U)
step (1)
expect(dut.io.out, 1)
poke(dut.io.a, 2.U)
poke(dut.io.b, 0.U)
step (1)
expect(dut.io.out, 0)
}
}
}
書き方1では結果が全て出力されるが、2では先に答えを入れておいて正しい答えが出力されたときにSuccessと表示するものになっている
ちなみにDUTはdesign under testって意味だお
いざ実行・・・の前にbuild.sbtに以下を付け足さなきゃいけないみたい
// バージョンを指定してchiselのiotestersをインストール
// 他のライブラリを使用するためには初回のダウンロードする必要があり?(よーわかってない)
libraryDependencies += "edu.berkeley.cs" %% "chisel-iotesters" % "1.3.1"
実行
// 1つめのテスト
$ sbt run
[info] running Test
[info] [0.001] Elaborating design...
[info] [0.517] Done elaborating.
Total FIRRTL Compile Time: 205.3 ms
file loaded in 0.032897348 seconds, 7 symbols, 3 statements
[info] [0.000] SEED 1575360902041
[info] [0.002] Result is: 0
[info] [0.002] Result is: 2
test DeviceUnderTest Success: 0 tests passed in 7 cycles in 0.008071 seconds 867.28 Hz
[info] [0.003] RAN 2 CYCLES PASSED
// 2つめのテスト
$ sbt run
[info] running Test
[info] [0.001] Elaborating design...
[info] [0.520] Done elaborating.
Total FIRRTL Compile Time: 204.3 ms
file loaded in 0.032164604 seconds, 7 symbols, 3 statements
[info] [0.000] SEED 1575361065328
test DeviceUnderTest Success: 2 tests passed in 7 cycles in 0.007838 seconds 893.12 Hz
[info] [0.003] RAN 2 CYCLES PASSED
できたあああああああああああああああああああうおおおおおおおおおおおおおおおおおおおおおおおお
回路の評価の際は1つめでゆる〜いチェックして、2つめで回路が完璧に動くかを判断するといいかも?
Packageとテストを組み合わせてみる
packageでライブラリ生成して実際にimportしたものを評価してみましょう!
package pack
import chisel3._
import chisel3.iotesters._
class DeviceUnderTest extends Module {
val io = IO(new Bundle {
val a = Input(UInt (2.W))
val b = Input(UInt (2.W))
val out = Output(UInt (2.W))
})
io.out := io.a & io.b
}
import pack._
import chisel3._
import chisel3.Driver
import chisel3.iotesters._
class Main extends Module {
val io = IO(new Bundle {
val a = Input(UInt(2.W))
val b = Input(UInt(2.W))
val out = Output(UInt(2.W))
})
// 実際に回路を使用する場合はModuleとして呼び出す必要がある
val d = Module(new DeviceUnderTest())
d.io.a := io.a
d.io.b := io.b
io.out := d.io.out
}
object Test extends App {
iotesters.Driver.execute(args, () => new Main){
c => new PeekPokeTester(c) {
poke(dut.io.a, 3.U)
poke(dut.io.b, 1.U)
step (1)
println("Result is: " + peek(dut.io.out).toString)
poke(dut.io.a, 2.U)
poke(dut.io.b, 0.U)
step (1)
println("Result is: " + peek(dut.io.out).toString)
}
}
}
まとめ
もう主要な機能はわかってきたから、とりあえず今回で締めかな?
あとはアーキテクチャやらアルゴリズムの理解の問題だと思われるので!
また重要なことがあればまとめます!
でも実際にChiselでRISCの設計をしてないから、とりあえずMipsでも作ってみよーかな
参考文献