diff --git a/src/main/scala/diplomacy/CloneModule.scala b/src/main/scala/diplomacy/CloneModule.scala new file mode 100644 index 00000000..bacb4c6c --- /dev/null +++ b/src/main/scala/diplomacy/CloneModule.scala @@ -0,0 +1,61 @@ +// See LICENSE.SiFive for license details. + +// !!! HACK TO WORK-AROUND MISSING CHISEL FEATURE +// !!! We need to be inside the chisel3 package to access Builder + +package chisel3.shim + +import Chisel._ +import chisel3.experimental.{RawModule, MultiIOModule, BaseModule} +import chisel3.internal.Builder +import chisel3.core.UserModule +import chisel3.internal.firrtl.{Command, DefInstance} +import scala.collection.immutable.ListMap +import scala.collection.mutable.ArrayBuffer + +class CloneModule private (model: RawModule) extends BlackBox +{ + import CloneModule._ + override def desiredName = model.name + val io = IO(new ClonePorts(model.getPorts.map(_.id): _*)) +} + +class HackDefInstance(imp: DefInstance, _name: => String) extends DefInstance(imp.sourceInfo, imp.id, imp.ports) +{ + override def name = _name +} + +object CloneModule +{ + def apply(model: BaseModule): ClonePorts = { + // Create the 'BlackBox' stand-in + val mod = Module(new CloneModule(model.asInstanceOf[RawModule])) + // Rewrite the instance definition to be the original module + // (this is needed because the original module gets clobbered by DCE + constant prop) + val method = classOf[UserModule].getDeclaredMethod("_commands") + method.setAccessible(true) + val commands = method.invoke(Builder.forcedUserModule).asInstanceOf[ArrayBuffer[Command]] + val victimIdx = commands.lastIndexWhere { + case DefInstance(_, kill, _) => mod eq kill + case _ => false + } + val victim = commands(victimIdx).asInstanceOf[DefInstance] + val standin = new HackDefInstance(victim.copy(id = model), victim.name) + commands.update(victimIdx, standin) + // Wire it up + model match { + case _: MultiIOModule => + mod.io("clock") := Module.clock + mod.io("reset") := Module.reset + case _: RawModule => // Do nothing + } + mod.io + } +} + +class ClonePorts(elts: Data*) extends Record +{ + val elements = ListMap(elts.map(d => d.instanceName -> d.chiselCloneType): _*) + def apply(field: String) = elements(field) + override def cloneType = (new ClonePorts(elts: _*)).asInstanceOf[this.type] +}