diff --git a/tapeout/src/main/scala/transforms/retime/Retime.scala b/tapeout/src/main/scala/transforms/retime/Retime.scala new file mode 100644 index 00000000..0f67adea --- /dev/null +++ b/tapeout/src/main/scala/transforms/retime/Retime.scala @@ -0,0 +1,45 @@ +// See LICENSE for license details. + +package barstools.tapeout.transforms.retime + +import chisel3.internal.InstanceId +import firrtl.PrimOps.Not +import firrtl.annotations.{Annotation, CircuitName, ModuleName, Named, ComponentName} +import firrtl.ir.{Input, UIntType, IntWidth, Module, Port, DefNode, NoInfo, Reference, DoPrim, Block, Circuit} +import firrtl.passes.Pass +import firrtl.{CircuitForm, CircuitState, LowForm, Transform} + +object RetimeAnnotation { + def apply(target: ModuleName): Annotation = Annotation(target, classOf[RetimeTransform], "retime") + def unapply(a: Annotation): Option[Named] = a match { + case Annotation(m, t, "retime") if t == classOf[RetimeTransform] => Some(m) + case _ => None + } +} + +class RetimeTransform extends Transform { + override def inputForm: CircuitForm = LowForm + override def outputForm: CircuitForm = LowForm + + override def execute(state: CircuitState): CircuitState = { + getMyAnnotations(state) match { + case Nil => state + case seq => seq.foreach { + case RetimeAnnotation(ModuleName(module, CircuitName(_))) => + logger.info(s"Retiming module $module") + case RetimeAnnotation(ComponentName(name, ModuleName(module, CircuitName(_)))) => + logger.info(s"Retiming instance $module.$name") + case _ => + throw new Exception(s"There should be RetimeAnnotations, got ${seq.mkString(" -- ")}") + } + state + } + } +} + +trait RetimeLib { + self: chisel3.Module => + def retime(component: InstanceId): Unit = { + annotate(chisel3.experimental.ChiselAnnotation(component, classOf[RetimeTransform], "retime")) + } +} diff --git a/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala b/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala new file mode 100644 index 00000000..bd52b5bc --- /dev/null +++ b/tapeout/src/test/scala/transforms/retime/RetimeSpec.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. + +package barstools.tapeout.transforms.retime.test + +import chisel3._ +import firrtl._ +import org.scalatest.{FlatSpec, Matchers} +import chisel3.experimental._ +import chisel3.util.HasBlackBoxInline +import chisel3.iotesters._ +import barstools.tapeout.transforms.retime._ + +class RetimeSpec extends FlatSpec with Matchers { + def normalized(s: String): String = { + require(!s.contains("\n")) + s.replaceAll("\\s+", " ").trim + } + def uniqueDirName[T](gen: => T, name: String): String = { + val genClassName = gen.getClass.getName + name + genClassName.hashCode.abs + } + + behavior of "retime library" + + it should "pass simple retime module annotation" in { + val gen = () => new RetimeModule() + val dir = uniqueDirName(gen, "RetimeModule") + chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final.anno"), gen) shouldBe a [ChiselExecutionSuccess] + + val lines = io.Source.fromFile(s"test_run_dir/$dir/final.anno").getLines().map(normalized).toSeq + lines should contain ("Annotation(ModuleName(RetimeModule,CircuitName(RetimeModule)),class barstools.tapeout.transforms.retime.RetimeTransform,retime)") + } + + // TODO(azidar): need to fix/add instance annotations + ignore should "pass simple retime instance annotation" in { + val gen = () => new RetimeInstance() + val dir = uniqueDirName(gen, "RetimeInstance") + chisel3.Driver.execute(Array("-td", s"test_run_dir/$dir", "-foaf", s"test_run_dir/$dir/final.anno"), gen) shouldBe a [ChiselExecutionSuccess] + + val lines = io.Source.fromFile(s"test_run_dir/$dir/final.anno").getLines().map(normalized).toSeq + lines should contain ("Annotation(ComponentName(instance, ModuleName(RetimeInstance,CircuitName(RetimeInstance))),class barstools.tapeout.transforms.retime.RetimeTransform,retime)") + } +} + +class RetimeModule extends Module with RetimeLib { + val io = IO(new Bundle { + val in = Input(UInt(15.W)) + val out = Output(UInt(15.W)) + }) + io.out := io.in + retime(this) +} + +class MyModule extends Module with RetimeLib { + val io = IO(new Bundle { + val in = Input(UInt(15.W)) + val out = Output(UInt(15.W)) + }) + io.out := io.in +} + +class RetimeInstance extends Module with RetimeLib { + val io = IO(new Bundle { + val in = Input(UInt(15.W)) + val out = Output(UInt(15.W)) + }) + val instance = Module(new MyModule) + retime(instance) + instance.io.in := io.in + io.out := instance.io.out +}