aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/scala/firrtl/Driver.scala5
-rw-r--r--src/main/scala/firrtl/ExecutionOptionsManager.scala10
-rw-r--r--src/main/scala/firrtl/transforms/CheckCombLoops.scala26
-rw-r--r--src/test/resources/features/HasLoops.fir9
-rw-r--r--src/test/scala/firrtlTests/CheckCombLoopsSpec.scala19
5 files changed, 62 insertions, 7 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index 5e3d046a..6c4c450b 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -12,7 +12,7 @@ import logger.Logger
import Parser.{IgnoreInfo, InfoMode}
import annotations._
import firrtl.annotations.AnnotationYamlProtocol._
-import firrtl.transforms.{BlackBoxSourceHelper, BlackBoxTargetDir}
+import firrtl.transforms.{BlackBoxSourceHelper, BlackBoxTargetDir, DontCheckCombLoopsAnnotation}
import Utils.throwInternalError
@@ -166,7 +166,8 @@ object Driver {
val outputAnnos = firrtlConfig.getEmitterAnnos(optionsManager)
// Should these and outputAnnos be moved to loadAnnotations?
- val globalAnnos = Seq(TargetDirAnnotation(optionsManager.targetDirName))
+ val globalAnnos = Seq(TargetDirAnnotation(optionsManager.targetDirName)) ++
+ (if (firrtlConfig.dontCheckCombLoops) Seq(DontCheckCombLoopsAnnotation()) else Seq())
val finalState = firrtlConfig.compiler.compile(
CircuitState(parsedInput,
diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala
index 76b497ec..ebe27a7d 100644
--- a/src/main/scala/firrtl/ExecutionOptionsManager.scala
+++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala
@@ -156,7 +156,8 @@ case class FirrtlExecutionOptions(
annotations: List[Annotation] = List.empty,
annotationFileNameOverride: String = "",
forceAppendAnnoFile: Boolean = false,
- emitOneFilePerModule: Boolean = false)
+ emitOneFilePerModule: Boolean = false,
+ dontCheckCombLoops: Boolean = false)
extends ComposableOptions {
require(!(emitOneFilePerModule && outputFileNameOverride.nonEmpty),
@@ -412,6 +413,13 @@ trait HasFirrtlOptions {
"Emit each module to its own file in the target directory."
}
+ parser.opt[Unit]("no-check-comb-loops")
+ .foreach { _ =>
+ firrtlOptions = firrtlOptions.copy(dontCheckCombLoops = true)
+ }.text {
+ "Do NOT check for combinational loops (not recommended)"
+ }
+
parser.note("")
}
diff --git a/src/main/scala/firrtl/transforms/CheckCombLoops.scala b/src/main/scala/firrtl/transforms/CheckCombLoops.scala
index d0eec02c..d2d8b449 100644
--- a/src/main/scala/firrtl/transforms/CheckCombLoops.scala
+++ b/src/main/scala/firrtl/transforms/CheckCombLoops.scala
@@ -11,6 +11,7 @@ import firrtl._
import firrtl.ir._
import firrtl.passes.{Errors, PassException}
import firrtl.Mappers._
+import firrtl.annotations._
import firrtl.Utils.throwInternalError
import firrtl.graph.{MutableDiGraph,DiGraph}
import firrtl.analyses.InstanceGraph
@@ -21,6 +22,16 @@ object CheckCombLoops {
}
+object DontCheckCombLoopsAnnotation {
+ private val marker = "DontCheckCombLoops!"
+ private val transform = classOf[CheckCombLoops]
+ def apply(): Annotation = Annotation(CircuitTopName, transform, marker)
+ def unapply(a: Annotation): Boolean = a match {
+ case Annotation(_, targetXform, value) if targetXform == transform && value == marker => true
+ case _ => false
+ }
+}
+
/** Finds and detects combinational logic loops in a circuit, if any
* exist. Returns the input circuit with no modifications.
*
@@ -179,7 +190,7 @@ class CheckCombLoops extends Transform {
* and only if it combinationally depends on input Y. Associate this
* reduced graph with the module for future use.
*/
- def run(c: Circuit): Circuit = {
+ private def run(c: Circuit): Circuit = {
val errors = new Errors()
/* TODO(magyar): deal with exmodules! No pass warnings currently
* exist. Maybe warn when iterating through modules.
@@ -210,8 +221,15 @@ class CheckCombLoops extends Transform {
}
def execute(state: CircuitState): CircuitState = {
- val result = run(state.circuit)
- CircuitState(result, outputForm, state.annotations, state.renames)
+ val dontRun = getMyAnnotations(state).collectFirst {
+ case DontCheckCombLoopsAnnotation() => true
+ }.getOrElse(false)
+ if (dontRun) {
+ logger.warn("Skipping Combinational Loop Detection")
+ state
+ } else {
+ val result = run(state.circuit)
+ CircuitState(result, outputForm, state.annotations, state.renames)
+ }
}
-
}
diff --git a/src/test/resources/features/HasLoops.fir b/src/test/resources/features/HasLoops.fir
new file mode 100644
index 00000000..e238761d
--- /dev/null
+++ b/src/test/resources/features/HasLoops.fir
@@ -0,0 +1,9 @@
+circuit HasLoops :
+ module HasLoops :
+ input i : UInt<1>
+ output o : UInt<1>
+ wire a : UInt<1>
+ wire b : UInt<1>
+ a <= and(b,i)
+ b <= not(a)
+ o <= add(a, UInt(1))
diff --git a/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala b/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala
index dfb61843..2c12d4ca 100644
--- a/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala
+++ b/src/test/scala/firrtlTests/CheckCombLoopsSpec.scala
@@ -8,6 +8,8 @@ import firrtl.passes._
import firrtl.transforms._
import firrtl.Mappers._
import annotations._
+import java.io.File
+import java.nio.file.Paths
class CheckCombLoopsSpec extends SimpleTransformSpec {
@@ -147,5 +149,22 @@ class CheckCombLoopsSpec extends SimpleTransformSpec {
compile(CircuitState(parse(input), ChirrtlForm, None), writer)
}
}
+}
+
+class CheckCombLoopsCommandLineSpec extends FirrtlFlatSpec {
+ val testDir = createTestDirectory("CombLoopChecker")
+ val inputFile = Paths.get(getClass.getResource("/features/HasLoops.fir").toURI()).toFile()
+ val outFile = new File(testDir, "HasLoops.v")
+ val args = Array("-i", inputFile.getAbsolutePath, "-o", outFile.getAbsolutePath, "-X", "verilog")
+
+ "Combinational loops detection" should "run by default" in {
+ a [CheckCombLoops.CombLoopException] should be thrownBy {
+ firrtl.Driver.execute(args)
+ }
+ }
+
+ it should "not run when given --no-check-comb-loops option" in {
+ firrtl.Driver.execute(args :+ "--no-check-comb-loops")
+ }
}