diff options
| author | Jack Koenig | 2021-06-22 09:52:53 -0700 |
|---|---|---|
| committer | GitHub | 2021-06-22 09:52:53 -0700 |
| commit | 11128d93ea5412508b2616fda862abf05a59b435 (patch) | |
| tree | b49535602228ced1d4891c675b9f3021dad144ea /src/main | |
| parent | ef4d9fc765ec1ccd336104c72bce7659bc9f4b64 (diff) | |
Fix VerilogMemDelays use before declaration (#2278)
The pass injects pipe registers immediately after the declaration of the
memory. This can be problematic if the clock for the associated memory
port is defined after the declaration of the memory. For any memory port
clocks that are driven by non-ports, we now inject a wire before the
pipe register declarations to be sure there are no
use-before-declaration issues.
Diffstat (limited to 'src/main')
| -rw-r--r-- | src/main/scala/firrtl/passes/memlib/VerilogMemDelays.scala | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/src/main/scala/firrtl/passes/memlib/VerilogMemDelays.scala b/src/main/scala/firrtl/passes/memlib/VerilogMemDelays.scala index a9b42eba..11184e60 100644 --- a/src/main/scala/firrtl/passes/memlib/VerilogMemDelays.scala +++ b/src/main/scala/firrtl/passes/memlib/VerilogMemDelays.scala @@ -56,6 +56,14 @@ object MemDelayAndReadwriteTransformer { private val metaChars = raw"[\[\]\.]".r private def flatName(e: Expression) = metaChars.replaceAllIn(e.serialize, "_") + /** Determines if all `RefLikeExpression` in this Expression are of kind [[PortKind]] */ + def allPortKinds(expr: Expression): Boolean = expr match { + case reflike: RefLikeExpression => kind(expr) == PortKind + case other => + other.foreach { (e: Expression) => if (!allPortKinds(e)) return false } // Early out + true + } + // Pipeline a group of signals with an associated valid signal. Gate registers when possible. def pipelineWithValid( ns: Namespace @@ -126,12 +134,28 @@ class MemDelayAndReadwriteTransformer(m: DefModule, passthroughSimpleSyncReadMem val rCmdDelay = if (mem.readUnderWrite == ReadUnderWrite.Old) 0 else mem.readLatency val rRespDelay = if (mem.readUnderWrite == ReadUnderWrite.Old) mem.readLatency else 0 val wCmdDelay = mem.writeLatency - 1 + val clockWires = new mutable.LinkedHashMap[WrappedExpression, (DefWire, Connect, Reference)] + // Memory port clocks may depend on something defined after the memory, create wires for clock + // Expressions that contain non-port references + def maybeInsertWire(expr: Expression): Expression = { + if (allPortKinds(expr)) expr + else { + def mkWire() = { + val wire = DefWire(NoInfo, ns.newName(s"${mem.name}_clock"), expr.tpe) + val ref = Reference(wire).copy(flow = SourceFlow) + val con = Connect(NoInfo, ref.copy(flow = SinkFlow), expr) + (wire, con, ref) + } + clockWires.getOrElseUpdate(we(expr), mkWire())._3 + } + } val readStmts = (mem.readers ++ mem.readwriters).map { case r => def oldDriver(f: String) = swapMemRefs(netlist(we(memPortField(mem, r, f)))) def newField(f: String) = memPortField(newMem, rMap.getOrElse(r, r), f) - val clk = oldDriver("clk") + // The memory port clock could depend on something defined after the memory + val clk = maybeInsertWire(oldDriver("clk")) // Pack sources of read command inputs into WithValid object -> different for readwriter val enSrc = if (rMap.contains(r)) AND(oldDriver("en"), NOT(oldDriver("wmode"))) else oldDriver("en") @@ -160,7 +184,8 @@ class MemDelayAndReadwriteTransformer(m: DefModule, passthroughSimpleSyncReadMem case w => def oldDriver(f: String) = swapMemRefs(netlist(we(memPortField(mem, w, f)))) def newField(f: String) = memPortField(newMem, wMap.getOrElse(w, w), f) - val clk = oldDriver("clk") + // The memory port clock could depend on something defined after the memory + val clk = maybeInsertWire(oldDriver("clk")) // Pack sources of write command inputs into WithValid object -> different for readwriter val cmdSrc = if (wMap.contains(w)) { @@ -180,8 +205,9 @@ class MemDelayAndReadwriteTransformer(m: DefModule, passthroughSimpleSyncReadMem SplitStatements(cmdDecls, cmdConns ++ cmdPortConns) } + newConns ++= clockWires.values.map(_._2) newConns ++= (readStmts ++ writeStmts).flatMap(_.conns) - Block(newMem +: (readStmts ++ writeStmts).flatMap(_.decls)) + Block(newMem +: clockWires.values.map(_._1) ++: (readStmts ++ writeStmts).flatMap(_.decls)) case sx: Connect if kind(sx.loc) == MemKind => val (memRef, _) = Utils.splitRef(sx.loc) // Filter old mem connections for *transformed* memories only |
