diff options
| author | Jim Lawson | 2016-06-21 09:17:30 -0700 |
|---|---|---|
| committer | Jim Lawson | 2016-06-21 09:17:30 -0700 |
| commit | d675043717593fb7e96fb0f1952debbeb7f20a57 (patch) | |
| tree | 75efcd84a40d0520421d0d40d9b9cc9fdba6df8d /chiselFrontend | |
| parent | 53813f61b7dfe246d214ab966739d01c65c8ecb0 (diff) | |
New Module, IO, Input/Output wrapping.
Diffstat (limited to 'chiselFrontend')
| -rw-r--r-- | chiselFrontend/src/main/scala/Chisel/Assert.scala | 4 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/Chisel/Module.scala | 66 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/Chisel/internal/Builder.scala | 26 |
3 files changed, 75 insertions, 21 deletions
diff --git a/chiselFrontend/src/main/scala/Chisel/Assert.scala b/chiselFrontend/src/main/scala/Chisel/Assert.scala index c086f014..4187c579 100644 --- a/chiselFrontend/src/main/scala/Chisel/Assert.scala +++ b/chiselFrontend/src/main/scala/Chisel/Assert.scala @@ -50,12 +50,12 @@ object assert { // scalastyle:ignore object.name } def apply_impl_do(cond: Bool, line: String, message: Option[String])(implicit sourceInfo: SourceInfo) { - when (!(cond || Builder.dynamicContext.currentModule.get.reset)) { + when (!(cond || Builder.forcedModule.reset)) { message match { case Some(str) => printf.printfWithoutReset(s"Assertion failed: $str\n at $line\n") case None => printf.printfWithoutReset(s"Assertion failed\n at $line\n") } - pushCommand(Stop(sourceInfo, Node(Builder.dynamicContext.currentModule.get.clock), 1)) + pushCommand(Stop(sourceInfo, Node(Builder.forcedModule.clock), 1)) } } diff --git a/chiselFrontend/src/main/scala/Chisel/Module.scala b/chiselFrontend/src/main/scala/Chisel/Module.scala index e2101538..4fba6b25 100644 --- a/chiselFrontend/src/main/scala/Chisel/Module.scala +++ b/chiselFrontend/src/main/scala/Chisel/Module.scala @@ -8,8 +8,9 @@ import scala.language.experimental.macros import internal._ import internal.Builder.pushCommand import internal.Builder.dynamicContext -import internal.firrtl._ import internal.sourceinfo.{SourceInfo, InstTransform, UnlocatableSourceInfo} +import internal.firrtl +import internal.firrtl.{Command, Component, DefInstance, DefInvalid, ModuleIO} object Module { /** A wrapper method that all Module instantiations must be wrapped in @@ -26,14 +27,19 @@ object Module { // module de-duplication in FIRRTL emission. val childSourceInfo = UnlocatableSourceInfo - val parent = dynamicContext.currentModule - val m = bc.setRefs() + val parent: Option[Module] = Builder.currentModule + val m = bc.setRefs() // This will set currentModule! m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs - dynamicContext.currentModule = parent + Builder.currentModule = parent // Back to parent! val ports = m.computePorts Builder.components += Component(m, m.name, ports, m._commands) - pushCommand(DefInstance(sourceInfo, m, ports)) - m.setupInParent(childSourceInfo) + // Avoid referencing 'parent' in top module + if(!Builder.currentModule.isEmpty) { + pushCommand(DefInstance(sourceInfo, m, ports)) + m.setupInParent(childSourceInfo) + } + + m } } @@ -52,10 +58,41 @@ extends HasId { def this(_reset: Bool) = this(None, Option(_reset)) def this(_clock: Clock, _reset: Bool) = this(Option(_clock), Option(_reset)) + // This function binds the iodef as a port in the hardware graph + private[Chisel] def Port[T<:Data](iodef: T): iodef.type = { + // Bind each element of the iodef to being a Port + Binding.bind(iodef, PortBinder(this), "Error: iodef") + iodef + } + + private[this] var ioDefined: Boolean = false + + /** + * This must wrap the datatype used to set the io field of any Module. + * i.e. All concrete modules must have defined io in this form: + * [lazy] val io[: io type] = IO(...[: io type]) + * + * Items in [] are optional. + * + * The granted iodef WILL NOT be cloned (to allow for more seamless use of + * anonymous Bundles in the IO) and thus CANNOT have been bound to any logic. + * This will error if any node is bound (e.g. due to logic in a Bundle + * constructor, which is considered improper). + * + * TODO(twigg): Specifically walk the Data definition to call out which nodes + * are problematic. + */ + def IO[T<:Data](iodef: T): iodef.type = { + require(!ioDefined, "Another IO definition for this module was already declared!") + ioDefined = true + + Port(iodef) + } + private[Chisel] val _namespace = Builder.globalNamespace.child private[Chisel] val _commands = ArrayBuffer[Command]() private[Chisel] val _ids = ArrayBuffer[HasId]() - dynamicContext.currentModule = Some(this) + Builder.currentModule = Some(this) /** Name of the instance. */ val name = Builder.globalNamespace.name(getClass.getName.split('.').last) @@ -64,8 +101,8 @@ extends HasId { * connections in and out of a Module may only go through `io` elements. */ def io: Bundle - val clock = Clock(INPUT) - val reset = Bool(INPUT) + val clock = Port(Input(Clock())) + val reset = Port(Input(Bool())) private[Chisel] def addId(d: HasId) { _ids += d } @@ -73,10 +110,13 @@ extends HasId { ("clk", clock), ("reset", reset), ("io", io) ) - private[Chisel] def computePorts = for((name, port) <- ports) yield { - val bundleDir = if (port.isFlip) INPUT else OUTPUT - Port(port, if (port.dir == NO_DIR) bundleDir else port.dir) - } + private[Chisel] def computePorts: Seq[firrtl.Port] = + for((name, port) <- ports) yield { + // Port definitions need to know input or output at top-level. + // By FIRRTL semantics, 'flipped' becomes an Input + val direction = if(Data.isFlipped(port)) Direction.Input else Direction.Output + firrtl.Port(port, direction) + } private[Chisel] def setupInParent(implicit sourceInfo: SourceInfo): this.type = { _parent match { diff --git a/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala b/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala index d0e28b7c..fddc4bd7 100644 --- a/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala +++ b/chiselFrontend/src/main/scala/Chisel/internal/Builder.scala @@ -41,11 +41,11 @@ private[Chisel] class IdGen { } private[Chisel] trait HasId { - private[Chisel] def _onModuleClose {} // scalastyle:ignore method.name - private[Chisel] val _parent = Builder.dynamicContext.currentModule + private[Chisel] def _onModuleClose: Unit = {} // scalastyle:ignore method.name + private[Chisel] val _parent: Option[Module] = Builder.currentModule _parent.foreach(_.addId(this)) - private[Chisel] val _id = Builder.idGen.next + private[Chisel] val _id: Long = Builder.idGen.next override def hashCode: Int = _id.toInt override def equals(that: Any): Boolean = that match { case x: HasId => _id == x._id @@ -93,15 +93,29 @@ private[Chisel] class DynamicContext { private[Chisel] object Builder { // All global mutable state must be referenced via dynamicContextVar!! private val dynamicContextVar = new DynamicVariable[Option[DynamicContext]](None) + private def dynamicContext: DynamicContext = + dynamicContextVar.value.getOrElse(new DynamicContext) - def dynamicContext: DynamicContext = - dynamicContextVar.value getOrElse (new DynamicContext) def idGen: IdGen = dynamicContext.idGen def globalNamespace: Namespace = dynamicContext.globalNamespace def components: ArrayBuffer[Component] = dynamicContext.components + def currentModule: Option[Module] = dynamicContext.currentModule + def currentModule_=(target: Option[Module]): Unit = { + dynamicContext.currentModule = target + } + def forcedModule: Module = currentModule match { + case Some(module) => module + case None => throw new Exception( + "Error: Not in a Module. Likely cause: Missed Module() wrap or bare chisel API call." + // A bare api call is, e.g. calling Wire() from the scala console). + ) + } + + // TODO(twigg): Ideally, binding checks and new bindings would all occur here + // However, rest of frontend can't support this yet. def pushCommand[T <: Command](c: T): T = { - dynamicContext.currentModule.foreach(_._commands += c) + forcedModule._commands += c c } def pushOp[T <: Data](cmd: DefPrim[T]): T = pushCommand(cmd).id |
