diff options
| author | Albert Magyar | 2021-03-09 22:27:52 -0800 |
|---|---|---|
| committer | Albert Magyar | 2021-04-05 12:00:02 -0700 |
| commit | bf5b51b101bd9ab0883cdfa56f8c42bf26a1f375 (patch) | |
| tree | d988bb31d1e5d9df14399349ee4ae04a2cd78a45 /src | |
| parent | 8a9dfa8b0324b3f52e676b9d27912656c43dd327 (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.scala | 57 |
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.") + } + } +} |
