diningyo / learning-chisel3

Repository for learning Chisel3

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

learning-chisel3

自分で書いたChiselのコードで後々見返したくなりそうなやつを集めておくリポジトリ。 大体はブログで取り上げてコードを一部掲載したものが多くなるはず。

必要なもの

以下の3つが動く環境

  • Scala
  • sbt - 1.2.7
  • verilator - 手元のバージョンは4.012

実行の方法

通常のsbt使ったプロジェクトと同様。
基本的にトピック毎にサブプロジェクトを作成していく予定なので、動かしたいプロジェクトに切り替えて実行するのが良い気がする。 なお以下に書いているコマンドはsbtを起動した状態で入力する形で記載しているので注意。

現在登録されているプロジェクト

chiselFlatSpec

その名の通りChiselFlatSpecについて調査した際にサンプルとして作成したプロジェクト。 以下で実行可能なはず。

project chiselFlatSpec
test

chiselFlasSpecWithArgs

ChiselFlatSpec使った形式のテストを実行する際にプログラム引数を渡す方法が無いかを試したプロジェクト。 Chiselのモジュール自体はChselFlatSpecプロジェクトと一緒で、テストモジュールに引数処理部分を追加したもの。 単純に実行するだけなら、以下で可能。

project chiselFlatSpecWithArgs
test

プログラム引数を使う場合は以下。

testOnly MyTester -- -D--backend-name=firrtl -D--generate-vcd-output=on -D--is-verbose=true

treadleOrFirrtlSim

ChiselのPeekPokeTesterを使った試験の際に遭遇した挙動の調査を行うためのサブプロジェクト(作りかけ)

project chiselFlatSpecWithArgs
test

プログラム引数を使う場合は以下。

testOnly MyTester -- -D--backend-name=firrtl -D--generate-vcd-output=on -D--is-verbose=true

xorShift

XorShiftを使った乱数生成回路用のサブプロジェクト。 Chiselのテスト用メモリのI/Fのタイミングをランダムにするために作ったやつ。 → 普通にVerilogで書いて埋めたほうが楽な気はするがそこは気にしない。 せっかくなので、ベタ書きのXorShift32版を元にリファクタリングしてChiselっぽく書き換えていくことにする。

project xorShift
test

bundleAlias

Bundleを使ってデータを構造化した場合に、Bundle配下のデータの名前が長いな、、どうにか出来るよね、これ。 というのを確認するためのサブプロジェクト。

例えば、わざとらしいけど以下のようなBundleを考えた時にio.a.bb.cccにアクセスしやすくすることが出来るかを確かめる

import chisel3._
import chisel3.util._

class A(hasOptPort: Boolean = true) extends Bundle {
  val a = new Bundle {
    val bb = new Bundle {
      val ccc = new Bundle {
        val d = Input(Bool())
        val e = Output(Bool())
        val f = Input(UInt(32.W))
        val g = if (hasOptPort) Some(Output(UInt(32.W))) else None
      }
    }
  }
}

class B(hasOptPort: Boolean = true) extends Module {
  val io = IO(new A)

  io.a.bb.ccc.e := io.a.bb.ccc.d       // Bundleで構造化していくと
  if (hasOptPort) {
    io.a.bb.ccc.g.get := io.a.bb.ccc.f // どんどん深くなっていく
  }
}
project bundleAlias
test

uintAndSIntShift

Chiselで算術右シフトのやり方をキャストをした際の挙動を調べたもの。

project uintAndSIntShift
test

parallelTestExecution

ScalaTestのParallelTestExecutionを使ってChiselFlatSpecを継承して作った テストクラス内のテストを並列実行する処理を確認するためのサブプロジェクト。

project parallelTestExecution

逐次実行する場合のコマンド

testOnly SequentialTester

並列実行する場合のコマンド

testOnly ParallelTester

loadChiselMem

Chiselのメモリにファイルから読み込んだデータを設定する機能を試した時のサブプロジェクト。

project loadChiselMem
testOnly MemoryTester

memND

ChiselのMemを使って2次元のメモリを作る方法を間検討した時に作成したサブプロジェクト。
System Verilogの以下の記述で出来ることをChiselで実現してみた。

reg [3:0][7:0] mem[0:1023]

RTLの生成コマンド

以下のコマンドで"subprj/mem-nd/src/main/scala/Mem2D.scala"内のMem2DクラスのRTLが生成される。

project memND
runMain ElaborateMem2D

生成したRTLは以下のディレクトリに格納される。"WithWrite"と入っているファイルはMemBaseクラスのwriteを使って書いた場合のRTLとなる。

  • rtl/mem2d
    • Mem2D.anno.json
    • Mem2D.fir
    • Mem2D.v
    • Mem2DWithWrite.anno.json
    • Mem2DWithWrite.fir
    • Mem2DWithWrite.v

テスト実行コマンド

以下のコマンドでテストが実行される。

 testOnly Mem2DTester

bareAPICall

モジュールのテストを作成していて出くわしたエラーに対しての確認用のプロジェクト。

project bareAPICall
runMain TestElaborateBeforeErrorMod
runMain TestElaborateRegenerateErrorModFail
runMain TestElaborateRegenerateErrorModOK

コードから抜粋して書くと、以下のようなコードを作るとエラボレートは通るがテスト時のexpectでエラーになる。

import chisel3._
import chisel3.util._

class RegenerateErrorMod extends Module {
  val io = IO(new Bundle {
    val out = Output(UInt(2.W))
  })

  val out = Wire(Vec(2, Bool()))

  out(0) := true.B
  out(1) := false.B

  io.out := out.asUInt()
}

object TestElaborateRegenerateErrorModFail extends App {
  //
  iotesters.Driver.execute(args, () => new RegenerateErrorMod()) {
    c => new PeekPokeTester(c) {
      // ここでUIntの各ビットを参照するとエラー
      expect(c.io.out(0), true)
      expect(c.io.out(1), true)
    }
  }
}

utilQueue

Chiselに含まれるutil.Queueのオプションによる挙動の違いを調査した際のもので、以下のブログ記事の確認コード。 調査したオプションはQueueの第3/第4になっているpipe/flow

project utilQueue
test

上記のテストコマンドを実行すると"test_run_dir"に以下の4つのディレクトリが生成され、ダンプした波形が確認可能。

  1. QueuePipeOffFlowOff
  2. QueuePipeOffFlowOn
  3. QueuePipeOnFlowOff
  4. QueuePipeOnFlowOn

chiselName

Chiselに入っているアノテーション@chiselNameの効果を確認するためのプロジェクト。 対応するのは以下の記事。

import chisel3._
import chisel3.util._

@chiselName
class TestMod extends Module {
  val io = IO(new Bundle {
    val a = Input(Bool())
    val b = Input(Bool())
    val c = Output(UInt(4.W))
  })
  when (io.a) {
    val innerReg = RegInit(5.U(4.W)) // こういうブロック内の変数に名前がつけられる機能
    innerReg := innerReg + 1.U
    when (io.b) {
      val innerRegB = innerReg + 1.U
      innerReg := innerRegB
    }
    io.c := innerReg
  } .otherwise {
    io.c := 10.U
  }
}

object Elaborate extends App {
  Driver.execute(Array(
    "-tn=TestMod",
    "-td=rtl/chiselName"
  ),
  () => new TestMod)
}
  • エラボレートの実行
project chiselName
runMain Elaborate

上記を実行すると

  • rtl/chiselName

にFIRRTL/RTLが生成されます。

trialNIC

Chiselのパラメタライズのお試し実装として作った簡単なNIC用のプロジェクト。 以下のブログ記事で紹介したもの。 記事の方では割愛したテストも含んでいます。

sbtのコマンドラインから以下を実行してプロジェクトを切り替えてください。

project trialNIC

テストの実行

tiralNICプロジェクトを選択した状態で、以下で各モジュール毎のテストを実行することが可能です。 各テストの内容についてはテスト用クラスの実装をご覧ください。

  • NICDecoder
testOnly testOnly NICArbiterTester
  • NICArbiter
testOnly NICArbiterTester
  • NICTop
testOnly NICTopTester

MultiIOModule

MultiIOModuleを使ったデバッグポート作成に関するサンプルプロジェクト

以下のブログ記事の内容

MultiIOModuleを使ったデバッグ用ポートについての作成

project multiIOModule
runMain Test

コードから抜粋して書くと、以下のようなコードでデバッグ用のポートをdbg_という接頭辞で作れる。

import chisel3._
import chisel3.util._

/**
  * デバッグポート用のBundle
  * @param bits
  */
class DebugIO(bits: Int) extends Bundle {
  val count = Output(UInt(bits.W))
  override def cloneType: this.type = new DebugIO(bits).asInstanceOf[this.type]
}

/**
  * MultiIOModule使ったデバッグポート作成のサンプル
  * @param debug
  */
class DebugWithMultiIOModule(debug: Boolean) extends MultiIOModule {

  val bits = log2Ceil(4)

  val io = IO(new Bundle {
    val in = Flipped(new SomeDataIO)
    val out = new SomeDataIO
  })
  val q = Module(new Queue(chiselTypeOf(io.in.bits), 4))

  q.io.enq <> io.in
  io.out <> q.io.deq

  // debug
  val dbgBits = if (debug) 32 else 0
  val dbg = IO(new DebugIO(dbgBits))

  dbg.count := q.io.count
}

blackboxCheck

BlackBoxでVerilog-HDLの階層化されたモジュールを読み込む方法を確認したプロジェクト

以下のブログ記事の内容

ChiselのBlackboxで複数のファイルから構成されるVerilog-HDLのモジュールを読み込む

project blackboxCheck
test

arbiterTest

RRArbiterでReady-Validのハンドシェイクのテストコードをどう書けばいいか確認した際のコード。

以下のブログ記事の内容

ChiselのArbiterのvalid/readyの調停テストコードが上手く作れなかった話

project arbiterTest
test

実行すると以下のように1つ目のテストがFAILします。これは意図通りに動かないというダメだった例を残してあるものです。

[info] ArbiterTester:
[info] RRArbiter
[info] - should 以下のテストを実行するとin(2)/in(3)のvalidが同時にLOWに落ちる *** FAILED ***
[info]   false was not true (ArbiterTester.scala:41)
[info] - should in(N).readyを取得してからvalidを制御するとうまくいく
[info] ScalaTest
[info] Run completed in 2 seconds, 41 milliseconds.
[info] Total number of tests run: 2
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 1, canceled 0, ignored 0, pending 0
[info] *** 1 TEST FAILED ***
[error] Failed: Total 2, Failed 1, Errors 0, Passed 1
[error] Failed tests:
[error] 	ArbiterTester
[error] (Test / test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 8 s, completed 2019/10/09 23:50:45

simWDT

Chiselのテスト環境を使用したテストを実行する際に、テストベンチのモジュール側にタイマーを入れてシミュレーションをタイムアウトする仕組みの確認コード。

概要

以下のような感じでタイマーをインスタンスした基底クラスを用意しておき、実際のテストベンチはこの基底クラスを継承して作成する。

import chisel3._
import chisel3.util._

/**
  * シミュレーションのトップモジュール
  * @param limit シミュレーションのMAXサイクル数
  * @param abortEn timeout時にassertでシミュレーションを終了するかどうか
  */
abstract class BaseSimDTM(limit: Int, abortEn: Boolean = true) extends Module {
  val io: BaseSimDTMIO
  val wdt = Module(new WDT(limit, abortEn))

  def connect(finish: Bool): Unit = {
    io.finish := finish
    io.timeout := wdt.io.timeout
  }
}

/**
  * テスト用のシミュレーショントップモジュール
  * @param limit シミュレーションのMAXサイクル数
  * @param abortEn timeout時にassertでシミュレーションを終了するかどうか
  */
class SimDTM(limit: Int, abortEn: Boolean = true) extends BaseSimDTM(limit, abortEn) {
  val io = IO(new Bundle with BaseSimDTMIO)

  connect(false.B)
}

ブログの記事は以下。

Chiselのシミュレーションを所定のサイクルで終了する方法

実行方法

project simWDT
test
  • 実行結果
    • 以下のように時間が来るとassertが発火してシミュレーションが終了する。
[info] [0.002] Elaborating design...
[info] [0.132] Done elaborating.
Total FIRRTL Compile Time: 440.7 ms
file loaded in 0.075331792 seconds, 24 symbols, 20 statements
[info] [0.001] SEED 1570717992611
[info] [0.002] step = 0
[info] [0.003] step = 1
[info] [0.003] step = 2
[info] [0.004] step = 3
[info] [0.004] step = 4
[info] [0.005] step = 5
[info] [0.005] step = 6
[info] [0.005] step = 7
[info] [0.006] step = 8
[info] [0.006] step = 9
[info] [0.006] step = 10
[info] [0.007] step = 11
[info] [0.007] step = 12
[info] [0.008] step = 13
[info] [0.008] step = 14
[info] [0.009] step = 15
[info] [0.009] step = 16
[info] [0.010] step = 17
[info] [0.011] step = 18
[info] [0.011] step = 19
Assertion failed: WDT is expired!!
    at BaseSimDTM.scala:25 assert(!timeout, "WDT is expired!!")
treadle.executable.StopException: Failure Stop: result 1

chisel32x

Chisel 3.2.0で変更のあった部分で気になる部分を確認した際のコード。 以下の機能の確認コードが含まれる。

プロジェクトの切り替え

project chisel32x

Mux使用時のDontCare指定

runMain ElaborateMuxDontCare

正常にエラボレートが終了し以下の2つのRTLが生成される。

  • rtl/chisel-3.2.0/MuxDontCare/MuxDontCare.v
  • rtl/chisel-3.2.x/MuxCaseDontCare/MuxCaseDontCare.v

BundleLiterals

runMain ElaborateBundleLiterals

以下のRTLが生成される。

  • rtl/chisel-3.2.x/TrialBundleLiterals/TrialBundleLiterals.v

Verilog形式のメモリ読み込みのサポート

以下がテスト用のコード

testOnly MemVerilogStyleTester

テスト実行結果は以下のようになる。

STARTING test_run_dir/chisel-3.2.x/MemVerilogStyle/MemVerilogStyleTester453628597/VMemVerilogStyle
[info] [0.002] SEED 1571625549898
[info] [0.011] c.io.rddata = 0x00000000
[info] [0.014] c.io.rddata = 0x00000001 // @によるアドレス指定で"1"だけずれて配置
[info] [0.015] c.io.rddata = 0x00000002
[info] [0.015] c.io.rddata = 0x00000000
[info] [0.017] c.io.rddata = 0x00000000
[info] [0.018] c.io.rddata = 0x00000000
[info] [0.019] c.io.rddata = 0x00000000
[info] [0.020] c.io.rddata = 0x00000000

MixedVec

MixedVecの使い方の確認

runMain ElaborateMixedVec

以下のRTLが生成される

  • rtl/chisel-3.2.x/BundleLiterals/TrialMixedVec.v

Strong enumsのサポート

"Strong Enums"と紹介されているChiselEnumの確認コード

runMain ElaborateStrongEnums
  • rtl/chisel-3.2.x/TrialStrongEnums/TrialStrongEnums.v

HasBlackBoxPath

HasBlackBoxPathに実装されたaddPathメソッドの動作確認のコード。sbtのディレクトリ構成で固定される{main, test}/resources/以外のパスにRTLを置いても読み込むことが可能。

testOnly TrialHasBlackBoxPathTester

シミュレーションの実行結果は以下のようにエラー無く終了する。

[info] TrialHasBlackBoxPathTester:
[info] - should addPathで指定したパスのRTLが読み込める
[info] ScalaTest
[info] Run completed in 2 seconds, 804 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.
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1

AsyncReset

非同期リセットの確認コード

runMain ElaborateTrialAsyncReset
  • rtl/chisel-3.2.x/TrialAsyncReset/TrialAsyncReset.v

chisel33x

Chisel 3.3.0で変更のあった部分で気になる部分を確認した際のコード。 以下の機能の確認コードが含まれる。

プロジェクトの切り替え

project chisel33x

RTL生成方法の変更(Driver.execute→ChiselStage)

Chisel 3.3.0からChiselのソースコードのエラボレート方法が、chisel3.Driver.executeからchisel3.stage.ChiselStageを使う形に変更になった。

runMain OldElaborate # Chisel 3.2.xまでの方法
runMain NewElaborate # Chisel 3.3.0からの方法

参考:Chisel3.3.0のリリースノートを確認した(2) - ChiselStageを使ったエラボレート

ChiselのSyncReadMemのアクセス競合時の動作に関するオプションの追加

ChiselのSyncReadMemruwという引数が追加され、同一アドレスへのアクセス競合時の動作を指定できるようになった。

runMain ElaborateSRMA # RTLの生成
runMain TestSRMA # テストの実行

参考:Chisel3.3.0のリリースノートを確認した(3) - SyncReadMemに追加された引数

@chiselNameの強化

アノテーション@chiselNameの機能が強化され、Chiselの型以外のクラスについてもアノテーションの効果が得られるようになった。 また、NoChiselNamePrefixという@chiselNameの効果を打ち消すトレイトが追加された。このトレイトを適用することで、冗長な名前が生成されるのを抑制できる。

runMain ElaborateChiselName # Non-Bundleのクラスに対しての@chiselNameの確認
runMain ElaborateNoChiselNamePrefix # NoChiselNamePrefixの確認

BitPatが空白をサポート

BitPatでセパレータとして空白 がサポートされた。

runMain ElaborateBitPatWithWS

参考:Chisel3.3.0のリリースノートを確認した(6) - 簡単なやつを3つ

FixedPointの拡張

FixedPointが拡張され、DoubleBigDecimalからの変換が出来るようになった。

runMain ExpandToFixedPoint

参考:Chisel3.3.0のリリースノートを確認した(6) - 簡単なやつを3つ

printfがTABをサポート

printfでTAB文字\tがサポートされた

runMain ElaborateTrialAsyncReset

参考:Chisel3.3.0のリリースノートを確認した(6) - 簡単なやつを3つ

About

Repository for learning Chisel3

License:MIT License


Languages

Language:Scala 96.8%Language:SystemVerilog 3.2%Language:Verilog 0.1%