diff options
Diffstat (limited to 'core/src/main/scala/chisel3/RawModule.scala')
| -rw-r--r-- | core/src/main/scala/chisel3/RawModule.scala | 131 |
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 - } - } -} |
