Chiselで配列を出力するために試行錯誤してみる。 まず、試行する中で余計な処理をするコードを片っ端から省いていく。ここは最適化に影響しそうなところだが、とりあえず無視。
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 42101e4e..d9d29295 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -960,7 +971,6 @@ class VerilogEmitter extends SeqTransform with Emitter { new BlackBoxSourceHelper, new ReplaceTruncatingArithmetic, new FlattenRegUpdate, - new DeadCodeElimination, passes.VerilogModulusCleanup, new VerilogRename, passes.VerilogPrep, diff --git a/src/main/scala/firrtl/LoweringCompilers.scala b/src/main/scala/firrtl/LoweringCompilers.scala index 05cdbe96..4af78394 100644 --- a/src/main/scala/firrtl/LoweringCompilers.scala +++ b/src/main/scala/firrtl/LoweringCompilers.scala @@ -62,7 +62,6 @@ class HighFirrtlToMiddleFirrtl extends CoreTransform { passes.PullMuxes, passes.ReplaceAccesses, passes.ExpandConnects, - passes.RemoveAccesses, passes.Uniquify, passes.ExpandWhens, passes.CheckInitialization, @@ -114,8 +113,7 @@ class LowFirrtlOptimization extends CoreTransform { new firrtl.transforms.ConstantPropagation, passes.SplitExpressions, new firrtl.transforms.CombineCats, - passes.CommonSubexpressionElimination, - new firrtl.transforms.DeadCodeElimination) + passes.CommonSubexpressionElimination) } /** Runs runs only the optimization passes needed for Verilog emission */ class MinimumLowFirrtlOptimization extends CoreTransform {
次に、配列参照のコードを出力するために、stringify
を拡張する。
diff --git a/src/main/scala/firrtl/SystemVerilogEmitter.scala b/src/main/scala/firrtl/SystemVerilogEmitter.scala index 478f2bd2..46cb95c7 100644 --- a/src/main/scala/firrtl/SystemVerilogEmitter.scala +++ b/src/main/scala/firrtl/SystemVerilogEmitter.scala @@ -266,6 +266,7 @@ class SystemVerilogEmitter extends VerilogEmitter with Emitter { // Turn types into strings, all ports must be GroundTypes val tpes = m.ports map { case Port(_, _, _, tpe: GroundType) => stringify(tpe) + case Port(_, _, _, tpe: VectorType) => stringify(tpe) case port: Port => error(s"Trying to emit non-GroundType Port $port") }
ここのコード変換がミソになる。VectorType
に使用する型を_: UIntType | _: SIntType | _: AnalogType
であれば、通常通り信号を生成し、そのあとに[${tpe.size}]
を接続することができる。これで、2次元配列を生成できる。
diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 42101e4e..d9d29295 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -219,6 +219,17 @@ class VerilogEmitter extends SeqTransform with Emitter { case ClockType | AsyncResetType | AsyncResetNType => "" case _ => throwInternalError(s"trying to write unsupported type in the Verilog Emitter: $tpe") } + def stringify(tpe: VectorType): String = { + val ground_type = tpe.tpe + val elem_type = ground_type match { + case (_: UIntType | _: SIntType | _: AnalogType) => + val wx = bitWidth(tpe) - 1 + if (wx > 0) s"[$wx:0]" else "" + case ClockType | AsyncResetType | AsyncResetNType => "" + case _ => throwInternalError(s"trying to write unsupported type in the Verilog Emitter: $tpe") + } + elem_type + s"[${tpe.size}]" + } def emit(x: Any)(implicit w: Writer): Unit = { emit(x, 0) } def emit(x: Any, top: Int)(implicit w: Writer): Unit = {
配列のアクセスに関しては、lowerName
で一度配列名だけ文字列に変換しておき、VectorType
の時はそれを無理に分解せずにそのまま落とし込む。
diff --git a/src/main/scala/firrtl/passes/LowerTypes.scala b/src/main/scala/firrtl/passes/LowerTypes.scala index f52e1e6b..0ee6b5e2 100644 --- a/src/main/scala/firrtl/passes/LowerTypes.scala +++ b/src/main/scala/firrtl/passes/LowerTypes.scala @@ -36,6 +36,8 @@ object LowerTypes extends Transform { case e: WRef => e.name case e: WSubField => s"${loweredName(e.expr)}$delim${e.name}" case e: WSubIndex => s"${loweredName(e.expr)}$delim${e.value}" + case e: WSubAccess => s"${loweredName(e.expr)}" } def loweredName(s: Seq[String]): String = s mkString delim def renameExps(renames: RenameMap, n: String, t: Type, root: String): Seq[String] = @@ -52,11 +54,10 @@ object LowerTypes extends Transform { renames.rename(root + e.serialize, subNames) subNames } - case (t: VectorType) => (0 until t.size).flatMap { i => - val subNames = renameExps(renames, WSubIndex(e, i, t.tpe,flow(e)), root) - renames.rename(root + e.serialize, subNames) - subNames - } + case (t: VectorType) => + val name = root + loweredName(e) + Seq(name) }
@@ -139,6 +140,7 @@ object LowerTypes extends Transform { def lowerTypesExp(memDataTypeMap: MemDataTypeMap, info: Info, mname: String)(e: Expression): Expression = e match { case e: WRef => e + case e: WSubAccess => e map lowerTypesExp(memDataTypeMap, info, mname) case (_: WSubField | _: WSubIndex) => kind(e) match { case InstanceKind => val (root, tail) = splitRef(e)
これでテストコードを流してみた。
circuit VecModules : module VecModules : input in: UInt<1>[4] input sel: UInt<2> output out : UInt<1> out <= in[sel]
生成コードは以下のようになる。配列アクセスが生成された!
module VecModules( input logic [3:0][4] in, input logic [1:0] sel, output logic out ); assign out = in[sel]; endmodule