aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorKevin Laeufer2021-06-15 16:36:50 -0700
committerGitHub2021-06-15 23:36:50 +0000
commit117054bb4cdc3c5abf34ba5c99f61bcd590871f0 (patch)
treedde8b24ea3a744e058165f98e77639ca3283833f /src/test
parent3ea95e720c8107a1c466b8cba1fc076bfbc296fa (diff)
make PresetRegAnnotation public (#2254)
* make PresetRegAnnotation public this annotation is useful outside the firrtl compiler: - to implement a pass that creates registers which need to be initialized at the beginning of simulation (e.g., for formal verification) - to support preset registers in treadle * add PresetRegAnnotation test and deal with annotation correctly in RemoveReset pass
Diffstat (limited to 'src/test')
-rw-r--r--src/test/scala/firrtlTests/PresetRegAnnotationSpec.scala81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/test/scala/firrtlTests/PresetRegAnnotationSpec.scala b/src/test/scala/firrtlTests/PresetRegAnnotationSpec.scala
new file mode 100644
index 00000000..5cd0f764
--- /dev/null
+++ b/src/test/scala/firrtlTests/PresetRegAnnotationSpec.scala
@@ -0,0 +1,81 @@
+package firrtlTests
+
+import firrtl._
+import firrtl.annotations.{CircuitTarget, PresetRegAnnotation}
+import firrtl.options.Dependency
+import firrtl.testutils.LeanTransformSpec
+import firrtl.transforms.PropagatePresetAnnotations
+import logger.{LogLevel, LogLevelAnnotation, Logger}
+
+import scala.collection.mutable
+
+/** Tests the use of the [[firrtl.annotations.PresetRegAnnotation]]
+ * from a pass that needs to create a register with an initial value.
+ */
+class PresetRegAnnotationSpec
+ extends LeanTransformSpec(Seq(Dependency(MakePresetRegs), Dependency[SystemVerilogEmitter])) {
+ behavior.of("PresetRegAnnotation")
+
+ val src =
+ """circuit test:
+ | module test:
+ | input clock : Clock
+ | output out : UInt<8>
+ |
+ | reg r : UInt<8>, clock with :
+ | reset => (UInt(0), UInt<8>("h7b"))
+ | out <= r
+ |""".stripMargin
+
+ val ll = LogLevel.Error
+
+ it should "allow passes to mark registers to be initialized" in {
+ val result = Logger.makeScope(Seq(LogLevelAnnotation(ll))) { compile(src) }
+ val verilog = result.getEmittedCircuit.value
+ val lines = verilog.split('\n').map(_.trim).toSet
+
+ // the register should be assigned its initial value
+ assert(lines.contains("reg [7:0] r = 8'h7b;"))
+ assert(lines.contains("assign out = r;"))
+
+ // no asynchronous reset should be emitted
+ assert(!lines.contains("if (reset) begin"))
+ assert(!lines.contains("always @(posedge clock or posedge reset) begin"))
+ }
+}
+
+/** Adds preset reg annotations for all registers that have:
+ * 1. reset = false
+ * 2. init = a literal
+ */
+private object MakePresetRegs extends Transform with DependencyAPIMigration {
+ // run on lowered firrtl
+ override def prerequisites = Seq(Dependency(firrtl.passes.ExpandWhens), Dependency(firrtl.passes.LowerTypes))
+ override def invalidates(a: Transform) = false
+ // since we generate PresetRegAnnotations, we need to run after preset propagation
+ override def optionalPrerequisites = Seq(Dependency[PropagatePresetAnnotations])
+ // we want to run before the actual Verilog is emitted
+ // we want to look at the reset value, which may be removed by the RemoveReset transform.
+ override def optionalPrerequisiteOf = Seq(Dependency[SystemVerilogEmitter], Dependency(firrtl.transforms.RemoveReset))
+
+ override def execute(state: CircuitState): CircuitState = {
+ val c = CircuitTarget(state.circuit.main)
+ val newAnnos = state.circuit.modules.flatMap(onModule(c, _))
+ state.copy(annotations = newAnnos ++: state.annotations)
+ }
+
+ private def onModule(c: CircuitTarget, m: ir.DefModule): List[PresetRegAnnotation] = m match {
+ case mod: ir.Module =>
+ val regs = mutable.ListBuffer[String]()
+ mod.foreachStmt(onStmt(_, regs))
+ val m = c.module(mod.name)
+ regs.map(r => PresetRegAnnotation(m.ref(r))).toList
+ case _ => List()
+ }
+
+ private def onStmt(s: ir.Statement, regs: mutable.ListBuffer[String]): Unit = s match {
+ case ir.DefRegister(_, name, _, _, reset, init) if reset == Utils.False() && Utils.isLiteral(init) =>
+ regs.append(name)
+ case other => other.foreachStmt(onStmt(_, regs))
+ }
+}