diff options
| author | Adam Izraelevitz | 2018-07-10 18:36:02 -0700 |
|---|---|---|
| committer | Jack Koenig | 2018-07-10 18:36:02 -0700 |
| commit | 6b02d09eb412df275d00930ab0e167b07fa61862 (patch) | |
| tree | d2e9933d7cd7c13f09f9a085e9a1efb61aa48ecf | |
| parent | a0d23c1192712be1a5970bb70bb8f0cbafbe4e11 (diff) | |
Combinational Dependency Annotation (#809)
| -rw-r--r-- | src/main/scala/firrtl/transforms/CheckCombLoops.scala | 22 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/CheckCombLoopsSpec.scala | 29 |
2 files changed, 47 insertions, 4 deletions
diff --git a/src/main/scala/firrtl/transforms/CheckCombLoops.scala b/src/main/scala/firrtl/transforms/CheckCombLoops.scala index e1e6cf63..98033a2f 100644 --- a/src/main/scala/firrtl/transforms/CheckCombLoops.scala +++ b/src/main/scala/firrtl/transforms/CheckCombLoops.scala @@ -24,6 +24,14 @@ object CheckCombLoops { case object DontCheckCombLoopsAnnotation extends NoTargetAnnotation +case class CombinationalPath(sink: ComponentName, sources: Seq[ComponentName]) extends Annotation { + override def update(renames: RenameMap): Seq[Annotation] = { + val newSources = sources.flatMap { s => renames.get(s).getOrElse(Seq(s)) } + val newSinks = renames.get(sink).getOrElse(Seq(sink)) + newSinks.map(snk => CombinationalPath(snk, newSources)) + } +} + /** Finds and detects combinational logic loops in a circuit, if any * exist. Returns the input circuit with no modifications. * @@ -181,7 +189,7 @@ class CheckCombLoops extends Transform { * and only if it combinationally depends on input Y. Associate this * reduced graph with the module for future use. */ - private def run(c: Circuit): Circuit = { + private def run(c: Circuit): (Circuit, Seq[Annotation]) = { val errors = new Errors() /* TODO(magyar): deal with exmodules! No pass warnings currently * exist. Maybe warn when iterating through modules. @@ -211,8 +219,14 @@ class CheckCombLoops extends Transform { errors.append(new CombLoopException(m.info, m.name, expandedCycle)) } } + val mn = ModuleName(c.main, CircuitName(c.main)) + val annos = simplifiedModuleGraphs(c.main).getEdgeMap.collect { case (from, tos) if tos.nonEmpty => + val sink = ComponentName(from.name, mn) + val sources = tos.map(x => ComponentName(x.name, mn)) + CombinationalPath(sink, sources.toSeq) + } errors.trigger() - c + (c, annos.toSeq) } def execute(state: CircuitState): CircuitState = { @@ -221,8 +235,8 @@ class CheckCombLoops extends Transform { logger.warn("Skipping Combinational Loop Detection") state } else { - val result = run(state.circuit) - CircuitState(result, outputForm, state.annotations, state.renames) + val (result, annos) = run(state.circuit) + CircuitState(result, outputForm, state.annotations ++ annos, state.renames) } } } diff --git a/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala b/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala index d09b4d06..ed498180 100644 --- a/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala +++ b/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala @@ -189,6 +189,35 @@ class CheckCombLoopsSpec extends SimpleTransformSpec { compile(CircuitState(parse(input), ChirrtlForm), writer) } } + + "Circuit" should "create an annotation" in { + val input = """circuit hasnoloops : + | module thru : + | input in1 : UInt<1> + | input in2 : UInt<1> + | output out1 : UInt<1> + | output out2 : UInt<1> + | out1 <= in1 + | out2 <= in2 + | module hasnoloops : + | input clk : Clock + | input a : UInt<1> + | output b : UInt<1> + | wire x : UInt<1> + | inst inner of thru + | inner.in1 <= a + | x <= inner.out1 + | inner.in2 <= x + | b <= inner.out2 + |""".stripMargin + + val writer = new java.io.StringWriter + val cs = compile(CircuitState(parse(input), ChirrtlForm), writer) + val mn = ModuleName("hasnoloops", CircuitName("hasnoloops")) + cs.annotations.collect { + case c @ CombinationalPath(ComponentName("b", `mn`), Seq(ComponentName("a", `mn`))) => c + }.nonEmpty should be (true) + } } class CheckCombLoopsCommandLineSpec extends FirrtlFlatSpec { |
