TileLinkを使ったデザインを作っていきたい。Diplomacyについて勉強を進めていくなかで、やはり自分でデザインを作ってどの程度コントロールできるのか確認していく。オリジナルのデザインを作り上げていこう。
まず理解しておかなければならないのは、DiplomacyはChiselそのものの機能ではないということ。DiplomacyはChiselを使ったうえで構築されるプラットフォームであり、そのライブラリ群はRocketChipの一部として提供されている。したがって、オリジナルのDiplomacyを使ったデザインを構築したいとなると、RocketChipの力を借りなければならない。
まずはその環境を整えていく。
RocketChipをサブモジュールとして使用するデザイン環境の構築
実現したい環境は以下のようになる。実際のDiplomacyを使ったデザインはsrc/main/scala
上に存在しており、そこではDiplomacyを使用している。このDiplomacyを活用するために、RocketChipをサブモジュールとして使用したい。
. ├── src │ ├── main │ └── test ├── rocketchip │ ├── LICENSE.Berkeley │ ├── LICENSE.SiFive │ ├── LICENSE.jtag ...
このために、Rocket-Chipをサブモジュールとして押し込んだ。この時にディレクトリ名はrocketchip
としている。何故だかわからないが、ディレクトリ名がrocket-chip
やrocket_chip
などだと上手く動かない。これは少し調べてみる必要がありそう。
そして、ルートに存在するbuild.sbt
に以下の記述を追加した。これはつまりrocketchip
のデザインをルートディレクトリのプロジェクトに挿入することを意味する。
build.sbt
lazy val rocketchip = project in file("rocketchip") lazy val root = (project in file(".")) .dependsOn(other_resource) .dependsOn(rocketchip)
まずはテストだ。以下のようなコードを作ってみる。
src/main/scala/TLUnitTest/TLUnitTest.scala
// package tlunittest package freechips.rocketchip.unittest import Chisel._ // import other_resource._ import freechips.rocketchip.config._ import freechips.rocketchip.amba.ahb._ import freechips.rocketchip.amba.apb._ import freechips.rocketchip.amba.axi4._ import freechips.rocketchip.subsystem.{BaseSubsystemConfig} import freechips.rocketchip.devices.tilelink._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.util._ class WithTLOriginalUnitTest extends Config((site, here, up) => { case UnitTests => (q: Parameters) => { implicit val p = q val txns = 1 * site(TestDurationMultiplier) val timeout = 50000 * site(TestDurationMultiplier) Seq( Module(new TLRAMSimpleTest(1, txns=15*txns, timeout=timeout)) )} }) class TLOriginalUnitTestConfig extends Config(new WithTLOriginalUnitTest ++ new WithTestDuration(1) ++ new BaseSubsystemConfig)
このTLOriginalUnitTestConfig
ではConfig
としてWithTLOriginalUnitTest
クラスを使用している。ここではUnitTests
を使用し、TLRAMSimpleTest
をインスタンスしてテストを開始する。このTLRAMSimpleTest
はどのような仕組みになっているのかというと、
rocketchip/src/main/scala/tilelink/SRAM.scala
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 } } 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 }
この構成はどのようになっているのかというと、Fuzzer
→ TLRAMModel
→ TLDelayer(0.25)
→ TLRAM
の順に接続される。
さて、ここからVerilogを生成していこう。Rocketの構成をそのまま真似ているので、Makefileをそのまま活用する。
sbt 'runMain freechips.rocketchip.unittest.Generator . freechips.rocketchip.unittest TestHarness freechips.rocketchip.unittest TLOriginalUnitTestConfig' ../../firrtl_origin/utils/bin/firrtl -td . -i freechips.rocketchip.unittest.TLOriginalUnitTestConfig.fir -X sverilog
最初のコマンドで、freechips.rocketchip.unittest.TLOriginalUnitTestConfig.fir
を生成する。次のfirrtlコマンドで、Verilogを生成する。
TestHarness.sv
module TestHarness( input logic clock, input logic reset, output logic io_success ); logic UnitTestSuite_clock; // @[TestHarness.scala 10:23] logic UnitTestSuite_reset; // @[TestHarness.scala 10:23] logic UnitTestSuite_io_finished; // @[TestHarness.scala 10:23] UnitTestSuite UnitTestSuite ( // @[TestHarness.scala 10:23] .clock(UnitTestSuite_clock), .reset(UnitTestSuite_reset), .io_finished(UnitTestSuite_io_finished) ); assign io_success = UnitTestSuite_io_finished; // @[TestHarness.scala 10:14] assign UnitTestSuite_clock = clock; assign UnitTestSuite_reset = reset; endmodule
上手くできたようだ。ただし生成フローとしてはもう少し何とかならないか?確認を進めていこう。