FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

TileLinkのDiplomacyを使った実際のデザインを試してみる

TileLinkはDiplomacyという方式を使って実装されており、それを理解するのは大変だ。実際に触ってみるのが一番良い気がする。 という訳で、RocketChipの中でTileLinkのユニットテストを行っているデザインを抽出して実行してみた。

使用したのは、RocketChipの以下のリビジョンだ。

commit d12c7497ced7436872f2486e5ab6f0021dc094c0 (HEAD, tag: v1.2.2, upstream/1.2.x)
Author: Jim Lawson <ucbjrl@berkeley.edu>
Date:   Wed Dec 18 12:38:41 2019 -0800

    Remove redundant scm definition in pomExtra.
    This causes Sonatype/Nexus to fail with:
    ```
    Invalid POM: /edu/berkeley/cs/rocketchip_2.12/1.2.2/rocketchip_2.12-1.2.2.pom: Parsing Error: Duplicated tag: 'scm' (position: START_TAG seen ...&lt;/developers>\n &lt;scm>... @37:10)
    ```

調べてみると、TileLinkを使ったデザインで、以下のコンフィグレーションがシンプルで良い気がする。

ag "extend Config"
...
../src/main/scala/unittest/Configs.scala:149:class TLSimpleUnitTestConfig extends Config(new WithTLSimpleUnitTests ++ new WithTestDuration(10) ++ new BaseSubsystemConfig)
...

このコンフィグレーションを確認してみる。TLSimpleUnitTestConfigというのは以下のような構成となっている。

  • src/main/scala/unittest/Configs.scala
class WithTLSimpleUnitTests extends Config((site, here, up) => {
  case UnitTests => (q: Parameters) => {
    implicit val p = q
    val txns = 100 * site(TestDurationMultiplier)
    val timeout = 50000 * site(TestDurationMultiplier)
    Seq(
      // Module(new TLUserTest(               txns=   txns, timeout=timeout)),
      Module(new TLRAMSimpleTest(1,        txns=15*txns, timeout=timeout)),
      Module(new TLRAMSimpleTest(4,        txns=15*txns, timeout=timeout)),
      Module(new TLRAMSimpleTest(16,       txns=15*txns, timeout=timeout)),
      Module(new TLRAMZeroDelayTest(4,     txns=15*txns, timeout=timeout)),
      Module(new TLRAMHintHandlerTest(     txns=15*txns, timeout=timeout)),
      Module(new TLFuzzRAMTest(            txns= 3*txns, timeout=timeout)),
      Module(new TLRR0Test(                txns= 3*txns, timeout=timeout)),
      Module(new TLRR1Test(                txns= 3*txns, timeout=timeout)),
      Module(new TLRAMRationalCrossingTest(txns= 3*txns, timeout=timeout)),
      Module(new TLRAMAsyncCrossingTest(   txns= 5*txns, timeout=timeout)),
      Module(new TLRAMAtomicAutomataTest(  txns=10*txns, timeout=timeout)),
      Module(new TLRAMECCTest(8, 4,        txns=15*txns, timeout=timeout)),
      Module(new TLRAMECCTest(4, 1,        txns=15*txns, timeout=timeout)),
      Module(new TLRAMECCTest(1, 1,        txns=15*txns, timeout=timeout)) ) }
})

これだけたくさんテストをすると時間がかかるので、一本だけ抽出する。

      Module(new TLRAMSimpleTest(1,        txns=15*txns, timeout=timeout)),

このTLRAMSimpleTestというのは、何をするテストだろうか。

  • src/main/scala/tilelink/SRAM.scala
class TLRAMSimpleTest(ramBeatBytes: Int, txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
  val dut = Module(LazyModule(new TLRAMSimple(ramBeatBytes, txns)).module)
  io.finished := dut.io.finished
}
class TLRAMSimple(ramBeatBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule {
  val fuzz = LazyModule(new TLFuzzer(txns))
  val model = LazyModule(new TLRAMModel("SRAMSimple"))
  val ram  = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff), beatBytes = ramBeatBytes))

  ram.node := TLDelayer(0.25) := model.node := fuzz.node

  lazy val module = new LazyModuleImp(this) with UnitTestModule {
    io.finished := fuzz.module.io.finished
  }
}

インスタンスされているのは、

  • fuzz : TLFuzzer ランダムなリクエストを発生する。
  • model : TLRAMModel("SRAMSimple") RAMモデル。
  • ram : TLRAM(AddressSet(0x0, 0x3ff), beatBytes = ramBeatBytes) 実際のRAM。

これらを順に接続していく。

  ram.node := TLDelayer(0.25) := model.node := fuzz.node

なんでRAMを2つ接続しているのか良く分からないが...

この時のTLRAMSimpleTestのオプションとして以下が設定されている。

  • ramBeatBytes = 1
  • txns = 15 * txns = 15 * 100 * site(TestDurationMultiplier) = 15 * 100 * 10 = 15000

となっているのだが、面倒なのでかなり短縮しよう。15本くらいリクエストを出せば十分だろう。

実際にコンフィグレーションを生成してみる。

make debug CONFIG=TLSimpleUnitTestConfig PROJECT=freechips.rocketchip.unittest

生成できたようだ。実行してみよう。

# dummyは本当はELFを指定するのだが使わないのでdummyとしている。
./emulator-freechips.rocketchip.unittest-TLSimpleUnitTestConfig-debug +verbose -voutput/wave.vcd dummy
Started UnitTest TLRAMSimpleTest
SRAMSimple G  0x1f7 - 0x1f7
SRAMSimple g  0x1f7 := 0xcd, undefined (uninitialized or prior overlapping puts)
SRAMSimple G  0x0fb - 0x0fb
...
SRAMSimple G  0x122 - 0x122
SRAMSimple g  0x122 := 0x5c, undefined (uninitialized or prior overlapping puts)
*** PASSED *** Completed after 1069 cycles
f:id:msyksphinz:20191222012001p:plain
GTKWaveでの確認結果。

一応正しくデザインが生成できたようだ。もう少し解析してみよう。