現在FIRRTLでは出力オプションに-X sverilog
を追加することができ、これは一応SystemVerilog出力用のコンパイラであるのだが、実際に適用してみると、
------------------------------------------------------------------------------ Warning: SystemVerilog Compiler behaves the same as the Verilog Compiler! ------------------------------------------------------------------------------
こんな感じで実はVerilogコンパイラと全く同じものを出してくる。
逆にいえばこのあたりはまだ試しようがあるということで、では本当にSystemVerilogCompilerを追加するためにはどうすればよいのか考えてみる。
ただし、すべてSystemVerilogの機能を適用することはもちろんできなくて、例えばSystemVerilog Interfaceなどは便利な機能ではあるのだが、FIRがそのようなインタフェースはサポートしていないし、Chiselから変換した場合でもFIRに変換された時点でインタフェースは消えてしまっているので適用できない。ここでは、制御構文や、ちょっとしたSystem Verilogっぽい記述を追加するためにはどうすればよいのか考えてみる。
まず、SystemVerilog向けのコンパイラクラスを作る。これは、Verilogコンパイラクラスを適当にコピーして作る。
src/main/scala/firrtl/SystemVerilogEmitter.scala
class SystemVerilogEmitter extends VerilogEmitter with Emitter { class SystemVerilogRender(description: Description, portDescriptions: Map[String, Description], m: Module, moduleMap: Map[String, DefModule])(implicit writer: Writer) { def this(m: Module, moduleMap: Map[String, DefModule])(implicit writer: Writer) { ...
SystemVerilogRender
もVerilogRender
をベースに拡張したかったのだが、Scalaの文法が良く分かっていないのでエラーを解消できなかった。仕方がないのでSystemVerilogRender
を作ってVerilogRender
をそのままコピーしてしまった。これでとりあえずSystemVerilogCompiler専用のRenderを作ることができる。
手始めに非常に小さなところから改造してみる。まずは、wire
とreg
の記法が非常に古臭いので、格好よくlogic
を使ってみることにする。以下のようにSystemVerilogCompilerの記述を変更した。
src/main/scala/firrtl/SystemVerilogEmitter.scala
... // Turn directions into strings (and AnalogType into inout) val dirs = m.ports map { case Port(_, name, dir, tpe) => (dir, tpe) match { case (_, AnalogType(_)) => "inout " // padded to length of output case (Input, _) => "input logic " case (Output, _) => "output logic" } } ...
... withoutDescription match { case sx@Connect(info, loc@WRef(_, _, PortKind | WireKind | InstanceKind, _), expr) => assign(loc, expr, info) case sx: DefWire => declare("logic", sx.name, sx.tpe, sx.info) case sx: DefRegister => declare("logic", sx.name, sx.tpe, sx.info) val e = wref(sx.name, sx.tpe) regUpdate(e, sx.clock, sx.reset, sx.init) initialize(e, sx.reset, sx.init) case sx: DefNode => declare("logic", sx.name, sx.value.tpe, sx.info) assign(WRef(sx.name, sx.value.tpe, NodeKind, SourceFlow), sx.value, sx.info) case sx: Stop => ...
この状態でビルドしてみる。
sbt assembly ./utils/bin/firrtl -td regress -i regress/tag_array.fir -X sverilog
regress/tag_array.sv
module tag_array_ext( input logic RW0_clk, input logic [5:0] RW0_addr, input logic [79:0] RW0_wdata, output logic [79:0] RW0_rdata, input logic RW0_en, input logic RW0_wmode, input logic [3:0] RW0_wmask ); logic mem_0_0_clk; logic [5:0] mem_0_0_addr; logic [31:0] mem_0_0_din; logic [31:0] mem_0_0_dout; logic mem_0_0_write_en; logic mem_0_1_clk; logic [5:0] mem_0_1_addr; logic [31:0] mem_0_1_din; logic [31:0] mem_0_1_dout; ...
一応、wire
, reg
はlogic
に変更することができた。これ以外の変更できる点を探していく。