aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlbert Magyar2021-03-01 09:21:55 -0800
committerAlbert Magyar2021-04-05 12:00:02 -0700
commit59f0d9d2dbcc74e9489f453106704e403c59df06 (patch)
tree0e3eac1f7e6404dae7180faad0169e012a84179c /src
parentbf5b51b101bd9ab0883cdfa56f8c42bf26a1f375 (diff)
Allow InferReadWrite to combine shared-address R/W ports when appropriate
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/passes/memlib/InferReadWrite.scala47
1 files changed, 32 insertions, 15 deletions
diff --git a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala
index 0bb94452..39c79bc6 100644
--- a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala
+++ b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala
@@ -78,6 +78,16 @@ object InferReadWritePass extends Pass {
case sx => sx
}
+ /* If the ports share the same address in an undefined-collision SyncReadMem, reads issued while the write
+ * is enabled are *always* undefined; we may treat the read as if it were gated by the complement of w.en.
+ * Though not a strict requirement, this currently applies only to single-cycle read/write memories.
+ * N.B. for aggregate-typed memories, the spec is conservative and 'undefined' is not a function of the
+ * write mask, allowing optimization regardless of mask value. This must be revisited if the spec changes.
+ */
+ private def canOptimizeCollidingRW(mem: DefMemory): Boolean = {
+ mem.readUnderWrite == ReadUnderWrite.Undefined && mem.readLatency == 1 && mem.writeLatency == 1
+ }
+
def inferReadWriteStmt(connects: Connects, repl: Netlist, stmts: Statements)(s: Statement): Statement = s match {
// infer readwrite ports only for non combinational memories
case mem: DefMemory if mem.readLatency > 0 =>
@@ -94,7 +104,10 @@ object InferReadWritePass extends Pass {
val proofOfMutualExclusion = wenProductTerms.find(a => renProductTerms.exists(b => checkComplement(a, b)))
val wclk = getOrigin(connects)(memPortField(mem, w, "clk"))
val rclk = getOrigin(connects)(memPortField(mem, r, "clk"))
- if (weq(wclk, rclk) && proofOfMutualExclusion.nonEmpty) {
+ val waddr = getOrigin(connects)(memPortField(mem, w, "addr"))
+ val raddr = getOrigin(connects)(memPortField(mem, r, "addr"))
+ val optimizeCollision = (weq(waddr, raddr) && canOptimizeCollidingRW(mem))
+ if (weq(wclk, rclk) && (proofOfMutualExclusion.nonEmpty || optimizeCollision)) {
val rw = namespace.newName("rw")
val rwExp = WSubField(WRef(mem.name), rw)
readwriters += rw
@@ -104,28 +117,32 @@ object InferReadWritePass extends Pass {
repl(memPortField(mem, r, "en")) = EmptyExpression
repl(memPortField(mem, r, "addr")) = EmptyExpression
repl(memPortField(mem, r, "data")) = WSubField(rwExp, "rdata")
- repl(memPortField(mem, w, "clk")) = EmptyExpression
- repl(memPortField(mem, w, "en")) = EmptyExpression
- repl(memPortField(mem, w, "addr")) = EmptyExpression
+ repl(memPortField(mem, w, "clk")) = WSubField(rwExp, "clk")
repl(memPortField(mem, w, "data")) = WSubField(rwExp, "wdata")
repl(memPortField(mem, w, "mask")) = WSubField(rwExp, "wmask")
- stmts += Connect(NoInfo, WSubField(rwExp, "wmode"), proofOfMutualExclusion.get)
- stmts += Connect(NoInfo, WSubField(rwExp, "clk"), wclk)
stmts += Connect(
NoInfo,
WSubField(rwExp, "en"),
DoPrim(Or, Seq(connects(memPortField(mem, r, "en")), connects(memPortField(mem, w, "en"))), Nil, BoolType)
)
- stmts += Connect(
- NoInfo,
- WSubField(rwExp, "addr"),
- Mux(
- connects(memPortField(mem, w, "en")),
- connects(memPortField(mem, w, "addr")),
- connects(memPortField(mem, r, "addr")),
- UnknownType
+ if (optimizeCollision) {
+ repl(memPortField(mem, w, "en")) = WSubField(rwExp, "wmode")
+ repl(memPortField(mem, w, "addr")) = WSubField(rwExp, "addr")
+ } else {
+ repl(memPortField(mem, w, "en")) = EmptyExpression
+ repl(memPortField(mem, w, "addr")) = EmptyExpression
+ stmts += Connect(NoInfo, WSubField(rwExp, "wmode"), proofOfMutualExclusion.get)
+ stmts += Connect(
+ NoInfo,
+ WSubField(rwExp, "addr"),
+ Mux(
+ connects(memPortField(mem, w, "en")),
+ connects(memPortField(mem, w, "addr")),
+ connects(memPortField(mem, r, "addr")),
+ UnknownType
+ )
)
- )
+ }
}
}
if (readwriters.isEmpty) mem