前回の記事で、どうにかFixedInputStreamが実行できるようになったが、これはテストベンチまですべてScalaで記述して常に同じ動作を繰り返す環境になっている。 これは嫌なので、Verilogなどを接続して外部から引数を渡し、自由にシミュレーションを実行できるようにしたい。
というわけで、以下のチュートリアルを進めて、さらにFireChipのオリジナルデザインを拡張していく。
Creating Simulation Model — FireSim documentation
まずは、ChiselのデザインとVerilogのデザインを接続するインタフェースを作らなければならない。
そこで、「実際にはVerilogのデザイン」なのだけれども、まずはScalaで型を作る。これにはBlackBox
というクラスを使用する。
class SimInputStream(w: Int) extends BlackBox(Map("DATA_BITS" -> IntParam(w))) { val io = IO(new Bundle { val clock = Input(Clock()) val reset = Input(Bool()) val out = Decoupled(UInt(w.W)) }) }
このインタフェースを接続するためにSimInputStreamConfig
コンフィグレーションを作成する。
さらにconnectSimInput
を定義し、VerilogとScalaをインタフェースするためのしくみを作る。
src/main/scala/example/Config.scala
class WithSimInputStream extends Config((site, here, up) => { case BuildTop => (clock: Clock, reset: Bool, p: Parameters) => { val top = Module(LazyModule(new ExampleTopWithInputStream()(p)).module) top.connectSimInput(clock, reset) top } }) class SimInputStreamConfig extends Config( new WithSimInputStream ++ new BaseExampleConfig)
src/main/scala/example/InputStream.scala
trait HasPeripheryInputStream { this: BaseSubsystem => private val portName = "input-stream" @@ -30,6 +41,13 @@ trait HasPeripheryInputStreamModuleImp extends LazyModuleImp { val fixed = Module(new FixedInputStream(data, outer.streamWidth)) stream_in <> fixed.io.out } + + def connectSimInput(clock: Clock, reset: Bool) { + val sim = Module(new SimInputStream(outer.streamWidth)) + sim.io.clock := clock + sim.io.reset := reset + stream_in <> sim.io.out + } }
そしてVerilog/C++のインタフェースを作成して接続していく。これは長いしCopy&Pasteなので割愛。
要点としては、Verilogで定義されたSimInputStream
とScalaで定義されたSimInputStream
をconnectSimInput
で接続する、ということ。
これができればあとはデータをC++インタフェース側からひたすら流し込むだけである。
src/main/resources/vsrc/SimInputStream.v
module SimInputStream #(DATA_BITS=64) ( input clock, input reset, output out_valid, input out_ready, output [DATA_BITS-1:0] out_bits ); bit __out_valid; ...
これでコンパイルを行い、シミュレーションを行った。
$ make CONFIG=SimInputStreamConfig $ dd if=/dev/urandom of=instream.img bs=32 count=1 1+0 records in 1+0 records out 32 bytes copied, 0.000306216 s, 105 kB/s $ hexdump instream.img 0000000 1d2b e182 6629 006e 46be 3532 06c6 f1f2 0000010 2d00 aece 4ef7 d17b 4500 513a fd1e ca96 0000020 $ ./simulator-example-SimInputStreamConfig +instream=instream.img ../tests/input-stream.riscv 006e6629e1821d2b f1f206c6353246be d17b4ef7aece2d00 ca96fd1e513a4500