summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/RawModule.scala
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/scala/chisel3/RawModule.scala')
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala131
1 files changed, 80 insertions, 51 deletions
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index 8eeda03c..bab1a5b1 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -3,30 +3,105 @@
package chisel3
import scala.util.Try
-import scala.annotation.nowarn
import chisel3.experimental.BaseModule
import chisel3.internal._
-import chisel3.internal.BaseModule.ModuleClone
import chisel3.internal.Builder._
import chisel3.internal.firrtl._
import _root_.firrtl.annotations.{IsModule, ModuleTarget}
import scala.collection.immutable.VectorBuilder
+import scala.collection.mutable.ArrayBuffer
/** Abstract base class for Modules that contain Chisel RTL.
* This abstract base class is a user-defined module which does not include implicit clock and reset and supports
* multiple IO() declarations.
*/
-@nowarn("msg=class Port") // delete when Port becomes private
abstract class RawModule extends BaseModule {
+
+ /** Hook to invoke hardware generators after the rest of the Module is constructed.
+ *
+ * This is a power-user API, and should not normally be needed.
+ *
+ * In rare cases, it is necessary to run hardware generators at a late stage, but still within the scope of the
+ * Module. In these situations, atModuleBodyEnd may be used to register such generators. For example:
+ *
+ * {{{
+ * class Example extends RawModule {
+ * atModuleBodyEnd {
+ * val extraPort0 = IO(Output(Bool()))
+ * extraPort0 := 0.B
+ * }
+ * }
+ * }}}
+ *
+ * Any generators registered with atModuleBodyEnd are the last code to execute when the Module is constructed. The
+ * execution order is:
+ *
+ * - The constructors of any super classes or traits the Module extends
+ * - The constructor of the Module itself
+ * - The atModuleBodyEnd generators
+ *
+ * The atModuleBodyEnd generators execute in the lexical order they appear in the Module constructor.
+ *
+ * For example:
+ *
+ * {{{
+ * trait Parent {
+ * // Executes first.
+ * val foo = ...
+ * }
+ *
+ * class Example extends Parent {
+ * // Executes second.
+ * val bar = ...
+ *
+ * atModuleBodyEnd {
+ * // Executes fourth.
+ * val qux = ...
+ * }
+ *
+ * atModuleBodyEnd {
+ * // Executes fifth.
+ * val quux = ...
+ * }
+ *
+ * // Executes third..
+ * val baz = ...
+ * }
+ * }}}
+ *
+ * If atModuleBodyEnd is used in a Definition, any generated hardware will be included in the Definition. However, it
+ * is currently not possible to annotate any val within atModuleBodyEnd as @public.
+ */
+ protected def atModuleBodyEnd(gen: => Unit): Unit = {
+ _atModuleBodyEnd += { () => gen }
+ }
+ private val _atModuleBodyEnd = new ArrayBuffer[() => Unit]
+
//
// RTL construction internals
//
// Perhaps this should be an ArrayBuffer (or ArrayBuilder), but DefModule is public and has Seq[Command]
// so our best option is to share a single Seq datastructure with that
private val _commands = new VectorBuilder[Command]()
- private[chisel3] def addCommand(c: Command) = {
+
+ /** The current region to which commands will be added. */
+ private var _currentRegion = _commands
+
+ private[chisel3] def changeRegion(newRegion: VectorBuilder[Command]): Unit = {
+ _currentRegion = newRegion
+ }
+
+ private[chisel3] def withRegion[A](newRegion: VectorBuilder[Command])(thunk: => A): A = {
+ var oldRegion = _currentRegion
+ changeRegion(newRegion)
+ val result = thunk
+ changeRegion(oldRegion)
+ result
+ }
+
+ private[chisel3] def addCommand(c: Command): Unit = {
require(!_closed, "Can't write to module after module close")
- _commands += c
+ _currentRegion += c
}
protected def getCommands: Seq[Command] = {
require(_closed, "Can't get commands before module close")
@@ -159,49 +234,3 @@ trait RequireSyncReset extends Module {
override private[chisel3] def mkReset: Bool = Bool()
}
-/** Mix with a [[RawModule]] to automatically connect DontCare to the module's ports, wires, and children instance IOs. */
-
-package object internal {
-
- import scala.annotation.implicitNotFound
- @implicitNotFound("You are trying to access a macro-only API. Please use the @public annotation instead.")
- trait MacroGenerated
-
- /** 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
- }
- }
-}