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 ...</developers>\n <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
= 1txns
=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
一応正しくデザインが生成できたようだ。もう少し解析してみよう。