summaryrefslogtreecommitdiff
path: root/chiselFrontend
diff options
context:
space:
mode:
authorJim Lawson2016-06-21 09:17:30 -0700
committerJim Lawson2016-06-21 09:17:30 -0700
commitd675043717593fb7e96fb0f1952debbeb7f20a57 (patch)
tree75efcd84a40d0520421d0d40d9b9cc9fdba6df8d /chiselFrontend
parent53813f61b7dfe246d214ab966739d01c65c8ecb0 (diff)
New Module, IO, Input/Output wrapping.
Diffstat (limited to 'chiselFrontend')
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Assert.scala4
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Module.scala66
-rw-r--r--chiselFrontend/src/main/scala/Chisel/internal/Builder.scala26
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