ChiselのハードウェアデザインからVerilogのRTLを生成し、Treadleでシミュレーションを実行する
ものすごくタイトルが長くなってしまった。調べても意外と出てこなかったのでメモしておく。
VerilogのRTLを生成する方法
この記事を参考に以下のように書いてみた。
package GenVerilogTest import chisel3._ class Top(in0Bits: Int, in1Bits: Int) extends Module { val io = IO(new Bundle { val in0 = Input(UInt(in0Bits.W)) val in1 = Input(UInt(in0Bits.W)) val out = Output(UInt((in0Bits + 1).W)) }) io.out := io.in0 + io.in1 } object Elabolate extends App { chisel3.Driver.execute(args, () => new Top(32, 32)) match { case ChiselExecutionSuccess(Some(_), emittedStr, Some(firrtlExecutionResult)) => { firrtlExecutionResult match { case firrtl.FirrtlExecutionSuccess(_, compiledFirrtl) => { println(compiledFirrtl) // FirrtlからVerilogに変換した結果が表示される println("") println(emittedStr) // Firrtlが表示される } case firrtl.FirrtlExecutionFailure(message) => throw new Exception(s"FirrtlBackend: Compile failed.") case _ => throw new Exception("Problem with compilation") } } } }
上記コードにおいてchisel3.Driver.execute(args, () => new Top(32, 32))
においてVerilogとFirrtlの2つを生成している。生成されたファイルはbuild.sbt
が置かれているディレクトリと同じ箇所に置かれる。
生成されたファイルは以下の通り。この程度ぐらいであればなんとか読めるレベルではある。
;buildInfoPackage: chisel3, version: 3.1.8, scalaVersion: 2.11.12, sbtVersion: 1.1.1, builtAtString: 2019-07-08 17:44:42.884, builtAtMillis: 1562607882884 circuit Top : module Top : input clock : Clock input reset : UInt<1> output io : {flip in0 : UInt<32>, flip in1 : UInt<32>, out : UInt<33>} node _T_11 = add(io.in0, io.in1) @[Top.scala 12:20] node _T_12 = tail(_T_11, 1) @[Top.scala 12:20] io.out <= _T_12 @[Top.scala 12:10]
module Top( // @[:@3.2] input clock, // @[:@4.4] input reset, // @[:@5.4] input [31:0] io_in0, // @[:@6.4] input [31:0] io_in1, // @[:@6.4] output [32:0] io_out // @[:@6.4] ); wire [32:0] _T_11; // @[Top.scala 12:20:@8.4] wire [31:0] _T_12; // @[Top.scala 12:20:@9.4] assign _T_11 = io_in0 + io_in1; // @[Top.scala 12:20:@8.4] assign _T_12 = io_in0 + io_in1; // @[Top.scala 12:20:@9.4] assign io_out = {{1'd0}, _T_12}; // @[Top.scala 12:10:@10.4] endmodule
また、FirrtlとVerilogへの変換結果は文字列としても受け取ることができる。
object Simulator { // buildした結果のFirrtlとVerilogの2つをタプルとして返す def build(args: Array[String]): (String, String)= { chisel3.Driver.execute(args, () => new Top(32, 32)) match { case ChiselExecutionSuccess(Some(_), firrtlSource, Some(firrtlExecutionResult)) => { firrtlExecutionResult match { case firrtl.FirrtlExecutionSuccess(_, verilogSource) => { (verilogSource, firrtlSource) } case firrtl.FirrtlExecutionFailure(message) => throw new Exception(s"FirrtlBackend: Compile failed.") case _ => throw new Exception("Problem with compilation") } } } } def main(args: Array[String]): Unit = { // .. Simulatorの定義 } }
上記コードのbuild関数では、戻り値の1つめがVerilogのコード、2つめがFirrtlのコードに対応する。
次に、Firrtlのコードを使ってシミュレーターを起動してみる。Treadleを使うと以下のように書くことができる。
class SimulatorOptionsManager extends TreadleOptionsManager object Simulator { // buildした結果のFirrtlとVerilogの2つをタプルとして返す def build(args: Array[String]): (String, String)= { // .. 上のコードを参考 } def main(args: Array[String]): Unit = { val (_, firrtlSource) = build(args) val optionsManager = new SimulatorOptionsManager // simulatorを作成する際のオプションを指定できるみたいなのだが、正直良くわかっていない optionsManager.setTargetDirName("simulator_run_dir") val simulator = TreadleTester(firrtlSource, optionsManager) // 生成されたFirrtl自体を渡す val maxCycles = 100 var cycles = 0 println("Running...") simulator.poke("io_in0", 1) // io.in0 ではなく、 io_in0 のようにアンダースコアでつないで表現する必要があるので注意 simulator.poke("io_in1", 2) while (simulator.peek("io_out") != 12 && cycles < maxCycles) { simulator.step(1) cycles += 1 simulator.poke("io_in0", 10) simulator.poke("io_in1", 2) println(s"Simulated $cycles cycles") val out = simulator.peek("io_out") println(s"output is $out") } } }
以下のような出力が出てくるはず。
[info] Compiling 1 Scala source to /mnt/src/GenVerilogTest/target/scala-2.11/classes ... [warn] there were three feature warnings; re-run with -feature for details [warn] one warning found [info] Done compiling. [info] Packaging /mnt/src/GenVerilogTest/target/scala-2.11/chisel-module-template_2.11-3.1.1.jar ... [info] Done packaging. [info] Running GenVerilogTest.Sumulator [info] [0.001] Elaborating design... [info] [0.689] Done elaborating. Total FIRRTL Compile Time: 240.4 ms Total FIRRTL Compile Time: 12.9 ms file loaded in 0.051272257 seconds, 7 symbols, 3 statements Running... Simulated 1 cycles output is 12 [success] Total time: 3 s, completed 2019/08/03 15:52:56 [IJ]sbt:chisel-module-template>