diff options
| author | Albert Magyar | 2021-03-01 09:21:55 -0800 |
|---|---|---|
| committer | Albert Magyar | 2021-04-05 12:00:02 -0700 |
| commit | 59f0d9d2dbcc74e9489f453106704e403c59df06 (patch) | |
| tree | 0e3eac1f7e6404dae7180faad0169e012a84179c /src | |
| parent | bf5b51b101bd9ab0883cdfa56f8c42bf26a1f375 (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.scala | 47 |
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 |
