aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlbert Magyar2021-03-09 22:27:52 -0800
committerAlbert Magyar2021-04-05 12:00:02 -0700
commitbf5b51b101bd9ab0883cdfa56f8c42bf26a1f375 (patch)
treed988bb31d1e5d9df14399349ee4ae04a2cd78a45 /src
parent8a9dfa8b0324b3f52e676b9d27912656c43dd327 (diff)
Add SetDefaultReadUnderWrite transform
* Optionally defines read-under-write behavior for all 'undefined' memories * Use DefaultReadFirstAnnotation to choose read-first default * Use DefaultWriteFirstAnnotation to choose write-first default * Seal DefaultReadUnderWriteAnnotation based on Jack's feedback
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/passes/memlib/SetDefaultReadUnderWrite.scala57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/main/scala/firrtl/passes/memlib/SetDefaultReadUnderWrite.scala b/src/main/scala/firrtl/passes/memlib/SetDefaultReadUnderWrite.scala
new file mode 100644
index 00000000..d5646099
--- /dev/null
+++ b/src/main/scala/firrtl/passes/memlib/SetDefaultReadUnderWrite.scala
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package firrtl.passes
+package memlib
+
+import firrtl._
+import firrtl.ir._
+import firrtl.options.{Dependency, OptionsException}
+import firrtl.annotations.NoTargetAnnotation
+
+sealed trait DefaultReadUnderWriteAnnotation extends NoTargetAnnotation
+
+/** This annotation directs the [[SetDefaultReadUnderWrite]] transform to assign a default value of 'old' (read-first
+ * behavior) to all synchronous-read memories with 'undefined' read-under-write parameters.
+ */
+case object DefaultReadFirstAnnotation extends DefaultReadUnderWriteAnnotation
+
+/** This annotation directs the [[SetDefaultReadUnderWrite]] transform to assign a default value of 'new' (write-first
+ * behavior) to all synchronous-read memories with 'undefined' read-under-write parameters.
+ */
+case object DefaultWriteFirstAnnotation extends DefaultReadUnderWriteAnnotation
+
+/**
+ * Adding a [[DefaultReadUnderWriteAnnotation]] and running the [[SetDefaultReadUnderWrite]] transform will cause all
+ * synchronous-read memories with 'undefined' read-under-write parameters to be assigned a default parameter value,
+ * either 'old' (read-first behavior) or 'new' (write-first behavior). This can help generate Verilog that is amenable
+ * to RAM macro inference for various FPGA tools, or it can be used to satisfy other downstream design constraints.
+ */
+class SetDefaultReadUnderWrite extends Transform with DependencyAPIMigration {
+ override def prerequisites = firrtl.stage.Forms.HighForm
+ override def optionalPrerequisites = Seq(Dependency[InferReadWrite])
+ override def optionalPrerequisiteOf = Seq(Dependency(VerilogMemDelays))
+ override def invalidates(a: Transform): Boolean = false
+
+ private def onStmt(defaultRUW: ReadUnderWrite.Value)(stmt: Statement): Statement = stmt match {
+ case mem: DefMemory if (mem.readLatency > 0 && mem.readUnderWrite == ReadUnderWrite.Undefined) =>
+ mem.copy(readUnderWrite = defaultRUW)
+ case s => s.mapStmt(onStmt(defaultRUW))
+ }
+
+ override def execute(state: CircuitState): CircuitState = {
+ val c = state.circuit
+ val ruwDefaults = state.annotations
+ .collect({
+ case DefaultReadFirstAnnotation => ReadUnderWrite.Old
+ case DefaultWriteFirstAnnotation => ReadUnderWrite.New
+ })
+ .toSet
+ if (ruwDefaults.size == 0) {
+ state
+ } else if (ruwDefaults.size == 1) {
+ state.copy(circuit = c.copy(modules = c.modules.map(m => m.mapStmt(onStmt(ruwDefaults.head)))))
+ } else {
+ throw new OptionsException("Conflicting default read-under-write settings.")
+ }
+ }
+}