diff options
| author | Stephen Twigg | 2016-04-27 16:46:23 -0700 |
|---|---|---|
| committer | Andrew Waterman | 2016-05-04 01:28:50 -0700 |
| commit | 73e35c55c7a3f4be98432fd275e0e0ae7db76d46 (patch) | |
| tree | 7822b910dd81112e0f0c586e08beb18426f62197 /src/main | |
| parent | 0ad47ff929aa084d6aff4d378b32968ef19b97c7 (diff) | |
Add HasId=Module|Data.suggestName, TransitName util
Often times the scala runtime reflection fails to find an appropriate
name for a given net. This commit tries to partially ameliorate the
issue by exposing a suggestName function onto HasId (i.e. Module, Data)
that the user can call to 'suggest' a name.
Only the first suggestion is taken so repeated calls to suggestName will
not change the name for that node. This type of name exposure is
slightly risky as there is a chance the same name is suggested in the
same namespace. Thus, naming within a Module occurs in two passes:
The suggestion phase is when the user calls suggestName, etc. Near the
'end,' the Module uses runtime reflection to suggest names as well.
The forcing phase is when all the nodes are run through and a name is
'forced' onto them, using the namespace to suggest alternatives if the
desired one is taken. If no suggestion is present, the default name is
T, as before.
Second, there is an issue that commonly comes up when a component
library creates intermediate logic and then only returns a piece, or
even a piece of a piece (like part of a module IO). Any names suggested
by the Module by reflection onto that return value are either lost or
not fully applied. This issue is resolved by TransitName. TransitName
attaches a hook to the suggestName function of a HasId. With that hook,
any time suggestName is called on the hooked ID, that name suggestion is
also applied to other nodes.
For example, if Queue(in) is called, then any attempts to name the
returned output DecoupledIO will actually translate to naming attempts
on the backing Queue.
Diffstat (limited to 'src/main')
| -rw-r--r-- | src/main/scala/Chisel/Module.scala | 6 | ||||
| -rw-r--r-- | src/main/scala/Chisel/internal/Builder.scala | 25 | ||||
| -rw-r--r-- | src/main/scala/Chisel/util/Decoupled.scala | 2 | ||||
| -rw-r--r-- | src/main/scala/Chisel/util/TransitName.scala | 21 |
4 files changed, 49 insertions, 5 deletions
diff --git a/src/main/scala/Chisel/Module.scala b/src/main/scala/Chisel/Module.scala index 22c1f9c3..cfcf5a48 100644 --- a/src/main/scala/Chisel/Module.scala +++ b/src/main/scala/Chisel/Module.scala @@ -76,16 +76,18 @@ abstract class Module(_clock: Clock = null, _reset: Bool = null) extends HasId { for ((port, name) <- ports) port.setRef(ModuleIO(this, _namespace.name(name))) + // Suggest names to nodes using runtime reflection val valNames = HashSet[String](getClass.getDeclaredFields.map(_.getName):_*) def isPublicVal(m: java.lang.reflect.Method) = m.getParameterTypes.isEmpty && valNames.contains(m.getName) val methods = getClass.getMethods.sortWith(_.getName > _.getName) for (m <- methods; if isPublicVal(m)) m.invoke(this) match { - case id: HasId => id.setRef(_namespace.name(m.getName)) + case (id: HasId) => id.suggestName(m.getName) case _ => } - _ids.foreach(_.setRef(_namespace.name("T"))) + // All suggestions are in, force names to every node. + _ids.foreach(_.forceName(default="T", _namespace)) _ids.foreach(_._onModuleClose) this } diff --git a/src/main/scala/Chisel/internal/Builder.scala b/src/main/scala/Chisel/internal/Builder.scala index f9d27a61..c7ecdaa0 100644 --- a/src/main/scala/Chisel/internal/Builder.scala +++ b/src/main/scala/Chisel/internal/Builder.scala @@ -52,9 +52,30 @@ private[Chisel] trait HasId { case _ => false } + // Facilities for 'suggesting' a name to this. + // Post-name hooks called to carry the suggestion to other candidates as needed + private var suggested_name: Option[String] = None + private val postname_hooks = scala.collection.mutable.ListBuffer.empty[String=>Unit] + // Only takes the first suggestion! + def suggestName(name: =>String): this.type = { + if(suggested_name.isEmpty) suggested_name = Some(name) + for(hook <- postname_hooks) { hook(name) } + this + } + private[Chisel] def addPostnameHook(hook: String=>Unit): Unit = postname_hooks += hook + + // Uses a namespace to convert suggestion into a true name + // Will not do any naming if the reference already assigned. + // (e.g. tried to suggest a name to part of a Bundle) + private[Chisel] def forceName(default: =>String, namespace: Namespace): Unit = + if(_ref.isEmpty) { + val candidate_name = suggested_name.getOrElse(default) + val available_name = namespace.name(candidate_name) + setRef(Ref(available_name)) + } + private var _ref: Option[Arg] = None private[Chisel] def setRef(imm: Arg): Unit = _ref = Some(imm) - private[Chisel] def setRef(name: => String): Unit = if (_ref.isEmpty) setRef(Ref(name)) private[Chisel] def setRef(parent: HasId, name: String): Unit = setRef(Slot(Node(parent), name)) private[Chisel] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index))) private[Chisel] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref)) @@ -91,7 +112,7 @@ private[Chisel] object Builder { dynamicContextVar.withValue(Some(new DynamicContext)) { errors.info("Elaborating design...") val mod = f - mod.setRef(globalNamespace.name(mod.name)) + mod.forceName(mod.name, globalNamespace) errors.checkpoint() errors.info("Done elaborating.") diff --git a/src/main/scala/Chisel/util/Decoupled.scala b/src/main/scala/Chisel/util/Decoupled.scala index 498af572..faee2a5f 100644 --- a/src/main/scala/Chisel/util/Decoupled.scala +++ b/src/main/scala/Chisel/util/Decoupled.scala @@ -175,6 +175,6 @@ object Queue q.io.enq.valid := enq.valid // not using <> so that override is allowed q.io.enq.bits := enq.bits enq.ready := q.io.enq.ready - q.io.deq + TransitName(q.io.deq, q) } } diff --git a/src/main/scala/Chisel/util/TransitName.scala b/src/main/scala/Chisel/util/TransitName.scala new file mode 100644 index 00000000..ec5a11cc --- /dev/null +++ b/src/main/scala/Chisel/util/TransitName.scala @@ -0,0 +1,21 @@ +package Chisel + +import internal.HasId + +object TransitName { + // The purpose of this is to allow a library to 'move' a name call to a more + // appropriate place. + // For example, a library factory function may create a module and return + // the io. The only user-exposed field is that given IO, which can't use + // any name supplied by the user. This can add a hook so that the supplied + // name then names the Module. + // See Queue companion object for working example + def apply[T<:HasId](from: T, to: HasId): T = { + from.addPostnameHook((given_name: String) => {to.suggestName(given_name)}) + from + } + def withSuffix[T<:HasId](suffix: String)(from: T, to: HasId): T = { + from.addPostnameHook((given_name: String) => {to.suggestName(given_name+suffix)}) + from + } +} |
