diff options
| author | Jack Koenig | 2018-02-27 18:07:11 -0800 |
|---|---|---|
| committer | GitHub | 2018-02-27 18:07:11 -0800 |
| commit | c7eb1570dfb1c7701ea32d1209982a053f3cec1d (patch) | |
| tree | 3f509b202d82841c5dad5588d1f953a25d389b44 /src/main/scala/firrtl/passes | |
| parent | b90fc784a1819c1d7905910130a7da022214bc22 (diff) | |
Refactor Annotations (#721)
- Old Annotation renamed to deprecated LegacyAnnotation
- Annotation is now a trait that can be extended
- New JsonProtocol for Annotation [de]serialization
- Replace AnnotationMap with AnnotationSeq
- Deprecate Transform.getMyAnnotations
- Update Transforms
- Turn on deprecation warnings
- Remove deprecated Driver.compile
- Make AnnotationTests abstract with Legacy and Json subclasses
- Add functionality to convert LegacyAnnotations of built-in annos
This will give a noisy warning and is more of a best effort than a
robust solution.
Fixes #475 Closes #609
Diffstat (limited to 'src/main/scala/firrtl/passes')
9 files changed, 100 insertions, 157 deletions
diff --git a/src/main/scala/firrtl/passes/Inline.scala b/src/main/scala/firrtl/passes/Inline.scala index 2e15f09c..0ba0c5d9 100644 --- a/src/main/scala/firrtl/passes/Inline.scala +++ b/src/main/scala/firrtl/passes/Inline.scala @@ -10,14 +10,9 @@ import firrtl.annotations._ // Datastructures import scala.collection.mutable -// Tags an annotation to be consumed by this pass -object InlineAnnotation { - def apply(target: Named): Annotation = Annotation(target, classOf[InlineInstances], "") - - def unapply(a: Annotation): Option[Named] = a match { - case Annotation(named, t, _) if t == classOf[InlineInstances] => Some(named) - case _ => None - } +/** Indicates that something should be inlined */ +case class InlineAnnotation(target: Named) extends SingleTargetAnnotation[Named] { + def duplicate(n: Named) = InlineAnnotation(n) } // Only use on legal Firrtl. Specifically, the restriction of @@ -37,18 +32,17 @@ class InlineInstances extends Transform { }.toSet, instNames) case InlineAnnotation(ModuleName(mod, cir)) => (modNames + ModuleName(mod, cir), instNames) case InlineAnnotation(ComponentName(com, mod)) => (modNames, instNames + ComponentName(com, mod)) - case _ => throw new PassException("Annotation must be InlineAnnotation") + case _ => (modNames, instNames) } } def execute(state: CircuitState): CircuitState = { // TODO Add error check for more than one annotation for inlining - // TODO Propagate other annotations - getMyAnnotations(state) match { - case Nil => CircuitState(state.circuit, state.form) - case myAnnotations => - val (modNames, instNames) = collectAnns(state.circuit, myAnnotations) - run(state.circuit, modNames, instNames, state.annotations) + val (modNames, instNames) = collectAnns(state.circuit, state.annotations) + if (modNames.nonEmpty || instNames.nonEmpty) { + run(state.circuit, modNames, instNames, state.annotations) + } else { + state } } @@ -92,7 +86,7 @@ class InlineInstances extends Transform { } - def run(c: Circuit, modsToInline: Set[ModuleName], instsToInline: Set[ComponentName], annos: Option[AnnotationMap]): CircuitState = { + def run(c: Circuit, modsToInline: Set[ModuleName], instsToInline: Set[ComponentName], annos: AnnotationSeq): CircuitState = { def getInstancesOf(c: Circuit, modules: Set[String]): Set[String] = c.modules.foldLeft(Set[String]()) { (set, d) => d match { diff --git a/src/main/scala/firrtl/passes/clocklist/ClockList.scala b/src/main/scala/firrtl/passes/clocklist/ClockList.scala index be4d99fc..fcc3cd5e 100644 --- a/src/main/scala/firrtl/passes/clocklist/ClockList.scala +++ b/src/main/scala/firrtl/passes/clocklist/ClockList.scala @@ -43,7 +43,7 @@ class ClockList(top: String, writer: Writer) extends Pass { // Inline the clock-only circuit up to the specified top module val modulesToInline = (c.modules.collect { case Module(_, n, _, _) if n != top => ModuleName(n, CircuitName(c.main)) }).toSet val inlineTransform = new InlineInstances - val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), None).circuit + val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), Seq()).circuit val topModule = inlinedCircuit.modules.find(_.name == top).getOrElse(throwInternalError(Some("no top module"))) // Build a hashmap of connections to use for getOrigins diff --git a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala index 24f25525..6c7b2e18 100644 --- a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala +++ b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala @@ -15,8 +15,13 @@ import memlib.AnalysisUtils._ import memlib._ import Mappers._ +case class ClockListAnnotation(target: ModuleName, outputConfig: String) extends + SingleTargetAnnotation[ModuleName] { + def duplicate(n: ModuleName) = ClockListAnnotation(n, outputConfig) +} + object ClockListAnnotation { - def apply(t: String): Annotation = { + def parse(t: String): ClockListAnnotation = { val usage = """ [Optional] ClockList List which signal drives each clock of every descendent of specified module @@ -45,16 +50,7 @@ Usage: case None => } val target = ModuleName(passModule, CircuitName(passCircuit)) - Annotation(target, classOf[ClockListTransform], outputConfig) - } - - def apply(target: ModuleName, outputConfig: String): Annotation = - Annotation(target, classOf[ClockListTransform], outputConfig) - - def unapply(a: Annotation): Option[(ModuleName, String)] = a match { - case Annotation(ModuleName(m, c), t, outputConfig) if t == classOf[ClockListTransform] => - Some((ModuleName(m, c), outputConfig)) - case _ => None + ClockListAnnotation(target, outputConfig) } } @@ -63,13 +59,16 @@ class ClockListTransform extends Transform { def outputForm = LowForm def passSeq(top: String, writer: Writer): Seq[Pass] = Seq(new ClockList(top, writer)) - def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match { - case Seq(ClockListAnnotation(ModuleName(top, CircuitName(state.circuit.main)), out)) => - val outputFile = new PrintWriter(out) - val newC = (new ClockList(top, outputFile)).run(state.circuit) - outputFile.close() - CircuitState(newC, state.form, state.annotations) - case Nil => state - case seq => error(s"Found illegal clock list annotation(s): $seq") + def execute(state: CircuitState): CircuitState = { + val annos = state.annotations.collect { case a: ClockListAnnotation => a } + annos match { + case Seq(ClockListAnnotation(ModuleName(top, CircuitName(state.circuit.main)), out)) => + val outputFile = new PrintWriter(out) + val newC = (new ClockList(top, outputFile)).run(state.circuit) + outputFile.close() + CircuitState(newC, state.form, state.annotations) + case Nil => state + case seq => error(s"Found illegal clock list annotation(s): $seq") + } } } diff --git a/src/main/scala/firrtl/passes/memlib/DecorateMems.scala b/src/main/scala/firrtl/passes/memlib/DecorateMems.scala index ad3616ad..c5302a38 100644 --- a/src/main/scala/firrtl/passes/memlib/DecorateMems.scala +++ b/src/main/scala/firrtl/passes/memlib/DecorateMems.scala @@ -16,11 +16,11 @@ class CreateMemoryAnnotations(reader: Option[YamlFileReader]) extends Transform import CustomYAMLProtocol._ val configs = r.parse[Config] val cN = CircuitName(state.circuit.main) - val oldAnnos = state.annotations.getOrElse(AnnotationMap(Seq.empty)).annotations + val oldAnnos = state.annotations val (as, pins) = configs.foldLeft((oldAnnos, Seq.empty[String])) { case ((annos, pins), config) => val source = SourceAnnotation(ComponentName(config.source.name, ModuleName(config.source.module, cN)), config.pin.name) (annos, pins :+ config.pin.name) } - state.copy(annotations = Some(AnnotationMap(as :+ PinAnnotation(cN, pins.toSeq)))) + state.copy(annotations = PinAnnotation(pins.toSeq) +: as) } } diff --git a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala index 73fec1ee..661d6df4 100644 --- a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala +++ b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala @@ -13,15 +13,7 @@ import firrtl.passes.memlib.AnalysisUtils.{Connects, getConnects, getOrigin} import WrappedExpression.weq import annotations._ -object InferReadWriteAnnotation { - def apply(t: String) = Annotation(CircuitName(t), classOf[InferReadWrite], "") - def apply(target: CircuitName) = Annotation(target, classOf[InferReadWrite], "") - def unapply(a: Annotation): Option[(CircuitName)] = a match { - case Annotation(CircuitName(t), transform, "") if transform == classOf[InferReadWrite] => - Some(CircuitName(t)) - case _ => None - } -} +case object InferReadWriteAnnotation extends NoTargetAnnotation // This pass examine the enable signals of the read & write ports of memories // whose readLatency is greater than 1 (usually SeqMem in Chisel). @@ -159,10 +151,13 @@ class InferReadWrite extends Transform with SeqTransformBased { ResolveKinds, ResolveGenders ) - def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match { - case Nil => state - case Seq(InferReadWriteAnnotation(CircuitName(state.circuit.main))) => + def execute(state: CircuitState): CircuitState = { + val runTransform = state.annotations.contains(InferReadWriteAnnotation) + if (runTransform) { val ret = runTransforms(state) CircuitState(ret.circuit, outputForm, ret.annotations, ret.renames) + } else { + state + } } } diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala index bf0612ac..5ac9e63e 100644 --- a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala +++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala @@ -14,19 +14,8 @@ import firrtl.annotations._ import wiring._ -/** Annotates the name of the pin to add for WiringTransform - */ -object PinAnnotation { - def apply(target: CircuitName, pins: Seq[String]): Annotation = { - Annotation(target, classOf[ReplaceMemMacros], s"pins:${pins.mkString(" ")}") - } - private val matcher = "pins:(.*)".r - def unapply(a: Annotation): Option[(CircuitName, Seq[String])] = a match { - case Annotation(CircuitName(c), _, matcher(rest)) => - Some((CircuitName(c), rest.split(" "))) - case _ => None - } -} +/** Annotates the name of the pins to add for WiringTransform */ +case class PinAnnotation(pins: Seq[String]) extends NoTargetAnnotation /** Replace DefAnnotatedMemory with memory blackbox + wrapper + conf file. * This will not generate wmask ports if not needed. @@ -221,19 +210,17 @@ class ReplaceMemMacros(writer: ConfWriter) extends Transform { val modules = c.modules map updateMemMods(namespace, nameMap, memMods) // print conf writer.serialize() - val pins = getMyAnnotations(state) match { - case Nil => Nil - case Seq(PinAnnotation(CircuitName(c), pins)) => pins + val pannos = state.annotations.collect { case a: PinAnnotation => a } + val pins = pannos match { + case Seq() => Nil + case Seq(PinAnnotation(pins)) => pins case _ => throwInternalError(Some(s"execute: getMyAnnotations - ${getMyAnnotations(state)}")) } - val annos = (pins.foldLeft(Seq[Annotation]()) { (seq, pin) => - seq ++ memMods.collect { - case m: ExtModule => SinkAnnotation(ModuleName(m.name, CircuitName(c.main)), pin) + val annos = pins.foldLeft(Seq[Annotation]()) { (seq, pin) => + seq ++ memMods.collect { + case m: ExtModule => SinkAnnotation(ModuleName(m.name, CircuitName(c.main)), pin) } - }) ++ (state.annotations match { - case None => Seq.empty - case Some(a) => a.annotations - }) - CircuitState(c.copy(modules = modules ++ memMods), inputForm, Some(AnnotationMap(annos))) + } ++ state.annotations + CircuitState(c.copy(modules = modules ++ memMods), inputForm, annos) } } diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala index 8cbf9da7..311813db 100644 --- a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala +++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala @@ -64,13 +64,15 @@ class ConfWriter(filename: String) { } } +case class ReplSeqMemAnnotation(inputFileName: String, outputConfig: String) extends NoTargetAnnotation + object ReplSeqMemAnnotation { - def apply(t: String): Annotation = { + def parse(t: String): ReplSeqMemAnnotation = { val usage = """ [Optional] ReplSeqMem Pass to replace sequential memories with blackboxes + configuration file -Usage: +Usage: --replSeqMem -c:<circuit>:-i:<filename>:-o:<filename> *** Note: sub-arguments to --replSeqMem should be delimited by : and not white space! @@ -80,30 +82,15 @@ Required Arguments: Optional Arguments: -i<filename> Specify the input configuration file (for additional optimizations) -""" +""" val passOptions = PassConfigUtil.getPassOptions(t, usage) val outputConfig = passOptions.getOrElse( - OutputConfigFileName, + OutputConfigFileName, error("No output config file provided for ReplSeqMem!" + usage) ) val inputFileName = PassConfigUtil.getPassOptions(t).getOrElse(InputConfigFileName, "") - val passCircuit = passOptions.getOrElse( - PassCircuitName, - error("No circuit name specified for ReplSeqMem!" + usage) - ) - val target = CircuitName(passCircuit) - Annotation(target, classOf[ReplSeqMem], s"$inputFileName $outputConfig") - } - - def apply(target: CircuitName, inputFileName: String, outputConfig: String): Annotation = - Annotation(target, classOf[ReplSeqMem], s"$inputFileName $outputConfig") - - private val matcher = "([^ ]*) ([^ ]+)".r - def unapply(a: Annotation): Option[(CircuitName, String, String)] = a match { - case Annotation(CircuitName(c), t, matcher(inputFileName, outputConfig)) if t == classOf[ReplSeqMem] => - Some((CircuitName(c), inputFileName, outputConfig)) - case _ => None + ReplSeqMemAnnotation(inputFileName, outputConfig) } } @@ -135,12 +122,13 @@ class ReplSeqMem extends Transform { new SimpleMidTransform(ResolveKinds), new SimpleMidTransform(ResolveGenders)) - def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match { - case Nil => state // Do nothing if there are no annotations - case p => (p.collectFirst { case a if (a.target == CircuitName(state.circuit.main)) => a }) match { - case Some(ReplSeqMemAnnotation(target, inputFileName, outputConfig)) => + def execute(state: CircuitState): CircuitState = { + val annos = state.annotations.collect { case a: ReplSeqMemAnnotation => a } + annos match { + case Nil => state // Do nothing if there are no annotations + case Seq(ReplSeqMemAnnotation(inputFileName, outputConfig)) => val inConfigFile = { - if (inputFileName.isEmpty) None + if (inputFileName.isEmpty) None else if (new File(inputFileName).exists) Some(new YamlFileReader(inputFileName)) else error("Input configuration file does not exist!") } diff --git a/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala b/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala index e132e369..d195ea55 100644 --- a/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala +++ b/src/main/scala/firrtl/passes/memlib/ResolveMemoryReference.scala @@ -8,15 +8,9 @@ import AnalysisUtils.eqMems import firrtl.Mappers._ import firrtl.annotations._ -/** A component, e.g. register etc. Must be declared only once under the TopAnnotation - */ -object NoDedupMemAnnotation { - def apply(target: ComponentName): Annotation = Annotation(target, classOf[ResolveMemoryReference], s"nodedupmem!") - - def unapply(a: Annotation): Option[ComponentName] = a match { - case Annotation(ComponentName(n, mn), _, "nodedupmem!") => Some(ComponentName(n, mn)) - case _ => None - } +/** A component, e.g. register etc. Must be declared only once under the TopAnnotation */ +case class NoDedupMemAnnotation(target: ComponentName) extends SingleTargetAnnotation[ComponentName] { + def duplicate(n: ComponentName) = NoDedupMemAnnotation(n) } /** Resolves annotation ref to memories that exactly match (except name) another memory @@ -46,10 +40,8 @@ class ResolveMemoryReference extends Transform { c copy (modules = c.modules map (m => m map updateMemStmts(m.name, uniqueMems, noDeDupeMems))) } def execute(state: CircuitState): CircuitState = { - val noDedups = getMyAnnotations(state) match { - case Nil => Seq.empty - case annos => - annos.collect { case NoDedupMemAnnotation(ComponentName(cn, _)) => cn } + val noDedups = state.annotations.collect { + case NoDedupMemAnnotation(ComponentName(cn, _)) => cn } state.copy(circuit=run(state.circuit, noDedups)) } diff --git a/src/main/scala/firrtl/passes/wiring/WiringTransform.scala b/src/main/scala/firrtl/passes/wiring/WiringTransform.scala index 01e6f83a..9a82f8a0 100644 --- a/src/main/scala/firrtl/passes/wiring/WiringTransform.scala +++ b/src/main/scala/firrtl/passes/wiring/WiringTransform.scala @@ -14,32 +14,16 @@ import WiringUtils._ /** A class for all exceptions originating from firrtl.passes.wiring */ case class WiringException(msg: String) extends PassException(msg) -/** An extractor of annotated source components */ -object SourceAnnotation { - def apply(target: ComponentName, pin: String): Annotation = - Annotation(target, classOf[WiringTransform], s"source $pin") - - private val matcher = "source (.+)".r - def unapply(a: Annotation): Option[(ComponentName, String)] = a match { - case Annotation(ComponentName(n, m), _, matcher(pin)) => - Some((ComponentName(n, m), pin)) - case _ => None - } +/** A component, e.g. register etc. Must be declared only once under the TopAnnotation */ +case class SourceAnnotation(target: ComponentName, pin: String) extends + SingleTargetAnnotation[ComponentName] { + def duplicate(n: ComponentName) = this.copy(target = n) } -/** An extractor of annotation sink components or modules */ -object SinkAnnotation { - def apply(target: Named, pin: String): Annotation = - Annotation(target, classOf[WiringTransform], s"sink $pin") - - private val matcher = "sink (.+)".r - def unapply(a: Annotation): Option[(Named, String)] = a match { - case Annotation(ModuleName(n, c), _, matcher(pin)) => - Some((ModuleName(n, c), pin)) - case Annotation(ComponentName(n, m), _, matcher(pin)) => - Some((ComponentName(n, m), pin)) - case _ => None - } +/** A module, e.g. ExtModule etc., that should add the input pin */ +case class SinkAnnotation(target: Named, pin: String) extends + SingleTargetAnnotation[Named] { + def duplicate(n: Named) = this.copy(target = n) } /** Wires a Module's Source Component to one or more Sink @@ -64,26 +48,30 @@ class WiringTransform extends Transform { new Wiring(w), ToWorkingIR ) - - def execute(state: CircuitState): CircuitState = getMyAnnotations(state) match { - case Nil => state - case p => - val sinks = mutable.HashMap[String, Seq[Named]]() - val sources = mutable.HashMap[String, ComponentName]() - p.foreach { - case SinkAnnotation(m, pin) => - sinks(pin) = sinks.getOrElse(pin, Seq.empty) :+ m - case SourceAnnotation(c, pin) => - sources(pin) = c - } - (sources.size, sinks.size) match { - case (0, p) => state - case (s, p) if (p > 0) => - val wis = sources.foldLeft(Seq[WiringInfo]()) { case (seq, (pin, source)) => - seq :+ WiringInfo(source, sinks(pin), pin) - } - transforms(wis).foldLeft(state) { (in, xform) => xform.runTransform(in) } - case _ => error("Wrong number of sources or sinks!") - } + def execute(state: CircuitState): CircuitState = { + val annos = state.annotations.collect { + case a @ (_: SinkAnnotation | _: SourceAnnotation) => a + } + annos match { + case Seq() => state + case p => + val sinks = mutable.HashMap[String, Seq[Named]]() + val sources = mutable.HashMap[String, ComponentName]() + p.foreach { + case SinkAnnotation(m, pin) => + sinks(pin) = sinks.getOrElse(pin, Seq.empty) :+ m + case SourceAnnotation(c, pin) => + sources(pin) = c + } + (sources.size, sinks.size) match { + case (0, p) => state + case (s, p) if (p > 0) => + val wis = sources.foldLeft(Seq[WiringInfo]()) { case (seq, (pin, source)) => + seq :+ WiringInfo(source, sinks(pin), pin) + } + transforms(wis).foldLeft(state) { (in, xform) => xform.runTransform(in) } + case _ => error("Wrong number of sources or sinks!") + } + } } } |
