diff options
| author | Aditya Naik | 2024-08-02 15:20:25 -0700 |
|---|---|---|
| committer | Aditya Naik | 2024-08-02 15:20:25 -0700 |
| commit | 8947a5900e390c19524ab3013b33f0a8ec07ea43 (patch) | |
| tree | 69426553c4a4155b30a3077c5c6b6e72d784e4e5 /core/src/main/scala/chisel3/internal | |
| parent | b058bdcf8c142641aacd92f9938fb350a90e0762 (diff) | |
Update Module.scala
Diffstat (limited to 'core/src/main/scala/chisel3/internal')
| -rw-r--r-- | core/src/main/scala/chisel3/internal/package.scala | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/core/src/main/scala/chisel3/internal/package.scala b/core/src/main/scala/chisel3/internal/package.scala new file mode 100644 index 00000000..25d9129f --- /dev/null +++ b/core/src/main/scala/chisel3/internal/package.scala @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: Apache-2.0 + +package chisel3 + +import firrtl.annotations.{IsModule, ModuleTarget} +import chisel3.experimental.BaseModule +import chisel3.internal.firrtl.{Component, DefModule} // TODO move to object ir +import chisel3.internal.Builder.Prefix +import chisel3.ChiselException + +import scala.util.Try +import scala.annotation.implicitNotFound +import scala.collection.mutable +import scala.quoted +import scala.quoted._ + +package object internal { + + /** Marker trait for modules that are not true modules */ + private[chisel3] trait PseudoModule extends BaseModule + + /* Check if a String name is a temporary name */ + def isTemp(name: String): Boolean = name.nonEmpty && name.head == '_' + + /** Creates a name String from a prefix and a seed + * @param prefix The prefix associated with the seed (must be in correct order, *not* reversed) + * @param seed The seed for computing the name (if available) + */ + def buildName(seed: String, prefix: Prefix): String = { + // Don't bother copying the String if there's no prefix + if (prefix.isEmpty) { + seed + } else { + // Using Java's String builder to micro-optimize appending a String excluding 1st character + // for temporaries + val builder = new java.lang.StringBuilder() + // Starting with _ is the indicator of a temporary + val temp = isTemp(seed) + // Make sure the final result is also a temporary if this is a temporary + if (temp) { + builder.append('_') + } + prefix.foreach { p => + builder.append(p) + builder.append('_') + } + if (temp) { + // We've moved the leading _ to the front, drop it here + builder.append(seed, 1, seed.length) + } else { + builder.append(seed) + } + builder.toString + } + } + + // Sanitizes a name, e.g. from a `HasId`, by stripping all non ANSI-C characters + private[chisel3] def sanitize(s: String, leadingDigitOk: Boolean = false): String = { + // TODO what character set does FIRRTL truly support? using ANSI C for now + def legalStart(c: Char) = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' + def legal(c: Char) = legalStart(c) || (c >= '0' && c <= '9') + val res = if (s.forall(legal)) s else s.filter(legal) + val headOk = (!res.isEmpty) && (leadingDigitOk || legalStart(res.head)) + if (headOk) res else s"_$res" + } + + // Workaround for https://github.com/chipsalliance/chisel/issues/4162 + // We can't use the .asTypeOf workaround because this is used to implement .asTypeOf + private[chisel3] def _padHandleBool[A <: Bits]( + x: A, + width: Int + )(using Quotes): A = x match { + case b: Bool if !b.isLit && width > 1 && Type.of[A] == Type.of[UInt] => + val _pad = Wire(UInt(width.W)) + _pad := b + _pad.asInstanceOf[A] // This cast is safe because we know A is UInt on this path + case u => u.pad(width) + } + + // Resize that to this width (if known) + // TODO fix the "take not member of A" error here + // private[chisel3] def _resizeToWidth[A <: Bits]( + // that: A, + // targetWidthOpt: Option[Int] + // )(fromUInt: UInt => A + // )(using Quotes): A = + // (targetWidthOpt, that.widthOption) match { + // case (Some(targetWidth), Some(thatWidth)) => + // if (targetWidth == thatWidth) that + // else if (targetWidth > thatWidth) _padHandleBool(that, targetWidth) + // else fromUInt(that.take(targetWidth)) + // case (Some(targetWidth), None) => fromUInt(_padHandleBool(that, targetWidth).take(targetWidth)) + // case (None, Some(thatWidth)) => that + // case (None, None) => that + // } + + /** Internal API for [[ViewParent]] */ + sealed private[chisel3] class ViewParentAPI extends RawModule() with PseudoModule { + // We must provide `absoluteTarget` but not `toTarget` because otherwise they would be exactly + // the same and we'd have no way to distinguish the kind of target when renaming view targets in + // the Converter + // Note that this is not overriding .toAbsoluteTarget, that is a final def in BaseModule that delegates + // to this method + private[chisel3] val absoluteTarget: IsModule = ModuleTarget(this.circuitName, "_$$AbsoluteView$$_") + + // This module is not instantiable + override private[chisel3] def generateComponent(): Option[Component] = None + override private[chisel3] def initializeInParent(): Unit = () + // This module is not really part of the circuit + _parent = None + + // Sigil to mark views, starts with '_' to make it a legal FIRRTL target + override def desiredName = "_$$View$$_" + + private[chisel3] val fakeComponent: Component = DefModule(this, desiredName, Nil, Nil) + } + + /** Special internal object representing the parent of all views + * + * @note this is a val instead of an object because of the need to wrap in Module(...) + * @note this is a lazy val so that calling functions in this package object doesn't create it + */ + private[chisel3] lazy val ViewParent = + Module.apply(new ViewParentAPI) + + + // TODO this exists in cats.Traverse, should we just use that? + private[chisel3] implicit class ListSyntax[A](xs: List[A]) { + def mapAccumulate[B, C](z: B)(f: (B, A) => (B, C)): (B, List[C]) = { + val (zz, result) = xs.foldLeft((z, List.empty[C])) { + case ((acc, res), a) => + val (accx, c) = f(acc, a) + (accx, c :: res) + } + (zz, result.reverse) + } + } + + /** This is effectively a "LazyVal" box type, we can create the object but delay executing the argument + * + * @note This is similar to cats.Eval.later but we don't depend on Cats + */ + private[chisel3] class Delayed[A](a: => A) { + lazy val value: A = a + } + private[chisel3] object Delayed { + def apply[A](a: => A): Delayed[A] = new Delayed(a) + } + + /** The list of banned type alias words which will cause generation of bad FIRRTL. These are usually + * keyword tokens that would be automatically lexed by firtool, and so cause parsing errors. + */ + private[chisel3] val illegalTypeAliases = Seq( + "FIRRTL", + "Clock", + "UInt", + "Reset", + "AsyncReset", + "Analog", + "Probe", + "RWProbe", + "version", + "type", + "circuit", + "parameter", + "input", + "output", + "extmodule", + "module", + "intmodule", + "intrinsic", + "defname", + "const", + "flip", + "reg", + "smem", + "cmem", + "mport", + "define", + "attach", + "inst", + "of", + "reset", + "printf", + "skip", + "node" + ) + + /** Similar to Seq.groupBy except that it preserves ordering of elements within each group */ + private[chisel3] def groupByIntoSeq[A, K](xs: Iterable[A])(f: A => K): Seq[(K, Seq[A])] = { + val map = mutable.LinkedHashMap.empty[K, mutable.ListBuffer[A]] + for (x <- xs) { + val key = f(x) + val l = map.getOrElseUpdate(key, mutable.ListBuffer.empty[A]) + l += x + } + map.view.map({ case (k, vs) => k -> vs.toList }).toList + } +} |
