From 7ad088503f1080962561bee5e4ce954af7330888 Mon Sep 17 00:00:00 2001 From: Angie Wang Date: Sun, 2 Apr 2017 04:12:31 -0700 Subject: [PATCH] [stevo]: add custom analog annotation (#20) --- .../scala/transforms/AnalogAnnotation.scala | 81 +++++++++++++++++++ .../src/main/scala/transforms/Generate.scala | 21 ++++- 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tapeout/src/main/scala/transforms/AnalogAnnotation.scala diff --git a/tapeout/src/main/scala/transforms/AnalogAnnotation.scala b/tapeout/src/main/scala/transforms/AnalogAnnotation.scala new file mode 100644 index 00000000..5c3ba63a --- /dev/null +++ b/tapeout/src/main/scala/transforms/AnalogAnnotation.scala @@ -0,0 +1,81 @@ +// See LICENSE for license details + +package barstools.tapeout.transforms + +import chisel3._ +import chisel3.experimental.ChiselAnnotation +import chisel3.util._ +import chisel3.testers.BasicTester +import chisel3.experimental.{Analog, attach} +import firrtl.ir.{AnalogType, Circuit, DefModule, Expression, HasName, Port, Statement, Type} +import firrtl.{CircuitForm, CircuitState, LowForm, Transform} +import firrtl.annotations.{Annotation, ModuleName, Named, ComponentName} +import firrtl.Mappers._ + +object AnalogRenamerAnnotation { + def apply(target: Named, value: String): Annotation = + Annotation(target, classOf[AnalogRenamer], value) + + def unapply(a: Annotation): Option[(ComponentName, String)] = a match { + case Annotation(named, t, value) if t == classOf[AnalogRenamer] => named match { + case c: ComponentName => Some((c, value)) + case _ => None + } + case _ => None + } +} + +class AnalogRenamer 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 annos => + val analogs = annos.collect { case AnalogRenamerAnnotation(ana, name) => (ana, name) } + state.copy(circuit = run(state.circuit, analogs)) + } + } + + def run(circuit: Circuit, annos: Seq[(ComponentName, String)]): Circuit = { + circuit map walkModule(annos) + } + def walkModule(annos: Seq[(ComponentName, String)])(m: DefModule): DefModule = { + val filteredAnnos = Map(annos.filter(a => a._1.module.name == m.name).map { + case (c, s) => c.name.replace(".", "_") -> s + }: _*) + m map walkStatement(filteredAnnos) map walkPort(filteredAnnos) + } + def walkStatement(annos: Map[String, String])(s: Statement): Statement = { + s map walkExpression(annos) + } + def walkPort(annos: Map[String, String])(p: Port): Port = { + if (annos.contains(p.name)) { + updateAnalogVerilog(annos(p.name))(p.tpe) + } + p + } + def walkExpression(annos: Map[String, String])(e: Expression): Expression = { + e match { + case h: HasName => + if (annos.contains(h.name)) e mapType updateAnalogVerilog(annos(h.name)) + case _ => + } + e + } + def updateAnalogVerilog(value: String)(tpe: Type): Type = { + tpe match { + case a: AnalogType => + a.verilogTpe = value + a + case t => t + } + } +} + +trait AnalogAnnotator { self: Module => + def renameAnalog(component: Analog, value: String): Unit = { + annotate(ChiselAnnotation(component, classOf[AnalogRenamer], value)) + } +} diff --git a/tapeout/src/main/scala/transforms/Generate.scala b/tapeout/src/main/scala/transforms/Generate.scala index 79bbd3b0..536ad7ae 100644 --- a/tapeout/src/main/scala/transforms/Generate.scala +++ b/tapeout/src/main/scala/transforms/Generate.scala @@ -110,6 +110,7 @@ sealed trait GenerateTopAndHarnessApp extends App with LazyLogging { val post = if (top) { Seq( new passes.memlib.InferReadWrite(), new passes.memlib.ReplSeqMem(), + new AnalogRenamer(), new passes.clocklist.ClockListTransform() ) } else Seq() @@ -151,12 +152,28 @@ sealed trait GenerateTopAndHarnessApp extends App with LazyLogging { Seq( new ConvertToExtMod((m) => m.name == synTop.get), new RemoveUnusedModules, - new RenameModulesAndInstances((m) => AllModules.rename(m)) + new RenameModulesAndInstances((m) => AllModules.rename(m)), + new AnalogRenamer() ) } // always the same for now - private def getSecondPhaseAnnotations: AnnotationMap = AnnotationMap(Seq.empty) + private def getSecondPhaseAnnotations: AnnotationMap = { + //Load annotations from file + val annotationArray = annoFile match { + case None => Array[Annotation]() + case Some(fileName) => { + val annotations = new File(fileName) + if(annotations.exists) { + val annotationsYaml = io.Source.fromFile(annotations).getLines().mkString("\n").parseYaml + annotationsYaml.convertTo[Array[Annotation]] + } else { + Array[Annotation]() + } + } + } + AnnotationMap(annotationArray) + } // Top Generation protected def firstPhase(top: Boolean, harness: Boolean): Unit = {