// SPDX-License-Identifier: Apache-2.0 package firrtl.passes package clocklist import firrtl._ import firrtl.ir._ import annotations._ import java.io.{CharArrayWriter, Writer} import wiring.WiringUtils.{getChildrenMap, getLineage} import ClockListUtils._ import Utils._ import memlib.AnalysisUtils._ /** Starting with a top module, determine the clock origins of each child instance. * Write the result to writer. */ class ClockList(top: String, writer: Writer) extends Pass { def run(c: Circuit): Circuit = { // Build useful datastructures val childrenMap = getChildrenMap(c) val moduleMap = c.modules.foldLeft(Map[String, DefModule]())((map, m) => map + (m.name -> m)) val lineages = getLineage(childrenMap, top) val outputBuffer = new CharArrayWriter // === Checks === // TODO(izraelevitz): Check all registers/memories use "clock" clock port // ============== // Clock sources must be blackbox outputs and top's clock val partialSourceList = getSourceList(moduleMap)(lineages) val sourceList = partialSourceList ++ moduleMap(top).ports.collect { case Port(i, n, Input, ClockType) => n } writer.append(s"Sourcelist: $sourceList \n") // Remove everything from the circuit, unless it has a clock type // This simplifies the circuit drastically so InlineInstances doesn't take forever. val onlyClockCircuit = RemoveAllButClocks.run(c) // Inline the clock-only circuit up to the specified top module val modulesToInline = (c.modules.collect { case Module(_, n, _, _) if n != top => ModuleName(n, CircuitName(c.main)) }).toSet val inlineTransform = new InlineInstances { override val inlineDelim = "$" } val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), Seq()).circuit val topModule = inlinedCircuit.modules.find(_.name == top).getOrElse(throwInternalError("no top module")) // Build a hashmap of connections to use for getOrigins val connects = getConnects(topModule) // Return a map from instance name to clock origin val origins = getOrigins(connects, "", moduleMap)(lineages) // If the clock origin is contained in the source list, label good (otherwise bad) origins.foreach { case (instance, origin) => val sep = if (instance == "") "" else "." if (!sourceList.contains(origin.replace('.', '$'))) { outputBuffer.append(s"Bad Origin of $instance${sep}clock is $origin\n") } else { outputBuffer.append(s"Good Origin of $instance${sep}clock is $origin\n") } } // Write to output file writer.write(outputBuffer.toString) // Return unchanged circuit c } }