Skip to content

Commit e40332d

Browse files
committed
[core] Add initial domain support
Add support for creating domains and domain types. Add a built-in ClockDomain type. This is very basic support initially and many things will not work, namely connections or compilation of these to anything meaningful. Signed-off-by: Schuyler Eldridge <[email protected]>
1 parent 88eae4d commit e40332d

File tree

21 files changed

+357
-38
lines changed

21 files changed

+357
-38
lines changed

core/src/main/scala/chisel3/BlackBox.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ package experimental {
126126
// Ports are named in the same way as regular Modules
127127
namePorts()
128128

129-
val firrtlPorts = getModulePorts.map { case port =>
130-
Port(port, port.specifiedDirection, UnlocatableSourceInfo)
129+
val firrtlPorts = getModulePortsAndLocators.map { case (port, _, associations) =>
130+
Port(port, port.specifiedDirection, associations, UnlocatableSourceInfo)
131131
}
132132
val component = DefBlackBox(this, name, firrtlPorts, SpecifiedDirection.Unspecified, params, getKnownLayers)
133133
_component = Some(component)
@@ -217,9 +217,14 @@ abstract class BlackBox(
217217
port.setRef(ModuleIO(this, _namespace.name(name)), force = true)
218218
}
219219

220+
// Note: BlackBoxes, because they have a single `io` cannot currently
221+
// support associations because associations require having multiple ports.
222+
// If this restriction is lifted, then this code should be updated.
223+
require(getAssociations.isEmpty, "BlackBoxes cannot support associations at this time, use an ExtModule")
220224
val firrtlPorts = namedPorts.map { namedPort =>
221-
Port(namedPort._2, namedPort._2.specifiedDirection, UnlocatableSourceInfo)
225+
Port(namedPort._2, namedPort._2.specifiedDirection, Seq.empty, UnlocatableSourceInfo)
222226
}
227+
223228
val component = DefBlackBox(this, name, firrtlPorts, io.specifiedDirection, params, getKnownLayers)
224229
_component = Some(component)
225230
_component

core/src/main/scala/chisel3/IO.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package chisel3
22

3+
import chisel3.domain
34
import chisel3.internal.{throwException, Builder}
45
import chisel3.experimental.{noPrefix, requireIsChiselType, SourceInfo}
56
import chisel3.properties.{Class, Property}

core/src/main/scala/chisel3/Module.scala

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -576,16 +576,23 @@ package experimental {
576576

577577
private val _ports = new ArrayBuffer[(Data, SourceInfo)]()
578578

579+
private val _associations = new HashMap[Data, LinkedHashSet[Data]]()
580+
581+
protected[chisel3] def getAssociations: scala.collection.immutable.Map[Data, LinkedHashSet[Data]] =
582+
_associations.toMap
583+
579584
// getPorts unfortunately already used for tester compatibility
580585
protected[chisel3] def getModulePorts: Seq[Data] = {
581586
require(_closed, "Can't get ports before module close")
582587
_ports.iterator.collect { case (d: Data, _) => d }.toSeq
583588
}
584589

585590
// gets Ports along with there source locators
586-
private[chisel3] def getModulePortsAndLocators: Seq[(Data, SourceInfo)] = {
591+
private[chisel3] def getModulePortsAndLocators: Seq[(Data, SourceInfo, Seq[Data])] = {
587592
require(_closed, "Can't get ports before module close")
588-
_ports.toSeq
593+
_ports.toSeq.map { case (port, info) =>
594+
(port, info, _associations.get(port).map(_.toSeq).getOrElse(Seq.empty[Data]))
595+
}
589596
}
590597

591598
/** Get IOs that are currently bound to this module.
@@ -608,6 +615,22 @@ package experimental {
608615

609616
protected def portsSize: Int = _ports.size
610617

618+
/* Associate a port of this module with one or more domains. */
619+
final def associate(port: Data, domain: Data, domains: Data*)(implicit si: SourceInfo): Unit = {
620+
val allDomains = Seq(domain) ++ domains
621+
if (!portsContains(port)) {
622+
Builder.error(s"""Unable to associate port '$port' to domains '${allDomains.mkString(
623+
", "
624+
)}' because the port does not exist in this module""")(si)
625+
println(getModulePorts)
626+
return
627+
}
628+
_associations.updateWith(port) {
629+
case Some(acc) => Some(acc ++= allDomains)
630+
case None => Some(LinkedHashSet.empty[Data] ++= allDomains)
631+
}
632+
}
633+
611634
/** Generates the FIRRTL Component (Module or Blackbox) of this Module.
612635
* Also closes the module so no more construction can happen inside.
613636
*/
@@ -618,7 +641,7 @@ package experimental {
618641
private[chisel3] def initializeInParent(): Unit
619642

620643
private[chisel3] def namePorts(): Unit = {
621-
for ((port, source) <- getModulePortsAndLocators) {
644+
for ((port, source, _) <- getModulePortsAndLocators) {
622645
port._computeName(None) match {
623646
case Some(name) =>
624647
if (_namespace.contains(name)) {
@@ -882,7 +905,7 @@ package experimental {
882905
private[chisel3] def addSecretIO[A <: Data](iodef: A)(implicit sourceInfo: SourceInfo): A = {
883906
val name = iodef._computeName(None).getOrElse("secret")
884907
iodef.setRef(ModuleIO(this, _namespace.name(name)))
885-
val newPort = new Port(iodef, iodef.specifiedDirection, sourceInfo)
908+
val newPort = new Port(iodef, iodef.specifiedDirection, Seq.empty, sourceInfo)
886909
if (_closed) {
887910
_component.get.secretPorts += newPort
888911
} else secretPorts += newPort
@@ -905,7 +928,9 @@ package experimental {
905928
* TODO(twigg): Specifically walk the Data definition to call out which nodes
906929
* are problematic.
907930
*/
908-
protected def IO[T <: Data](iodef: => T)(implicit sourceInfo: SourceInfo): T = {
931+
protected def IO[T <: Data](iodef: => T)(
932+
implicit sourceInfo: SourceInfo
933+
): T = {
909934
chisel3.IO.apply(iodef)
910935
}
911936

core/src/main/scala/chisel3/RawModule.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ abstract class RawModule extends BaseModule {
9191
private var _firrtlPorts: Option[Seq[Port]] = None
9292

9393
private[chisel3] def checkPorts(): Unit = {
94-
for ((port, source) <- getModulePortsAndLocators) {
94+
for ((port, source, _) <- getModulePortsAndLocators) {
9595
if (port._computeName(None).isEmpty) {
9696
Builder.error(
9797
s"Unable to name port $port in $this, " +
@@ -175,8 +175,8 @@ abstract class RawModule extends BaseModule {
175175
nameId(id)
176176
}
177177

178-
val firrtlPorts = getModulePortsAndLocators.map { case (port, sourceInfo) =>
179-
Port(port, port.specifiedDirection, sourceInfo)
178+
val firrtlPorts = getModulePortsAndLocators.map { case (port, sourceInfo, associations) =>
179+
Port(port, port.specifiedDirection, associations, sourceInfo)
180180
}
181181
_firrtlPorts = Some(firrtlPorts)
182182

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3.domain
4+
5+
import chisel3.experimental.SourceInfo
6+
import chisel3.util.simpleClassName
7+
8+
object Field {
9+
sealed trait Type
10+
11+
object Boolean extends Type
12+
object Integer extends Type
13+
object String extends Type
14+
}
15+
16+
abstract class Domain()(implicit val sourceInfo: SourceInfo) { self: Singleton =>
17+
18+
private[chisel3] def name: String = simpleClassName(this.getClass())
19+
20+
def fields: Seq[(String, Field.Type)] = Seq.empty
21+
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3.domain
4+
5+
import chisel3.{fromIntToLiteral, Data, Element, Printable, UInt, UnknownWidth, Width}
6+
import chisel3.experimental.SourceInfo
7+
import chisel3.internal.{throwException, Builder}
8+
9+
final class Type private (val domain: Domain) extends Element { self =>
10+
11+
private[chisel3] def _asUIntImpl(first: Boolean)(implicit sourceInfo: SourceInfo): chisel3.UInt = {
12+
Builder.error(s"${this._localErrorContext} does not support .asUInt.")
13+
0.U
14+
}
15+
16+
override protected def _fromUInt(that: UInt)(implicit sourceInfo: SourceInfo): Data = {
17+
Builder.exception(s"${this._localErrorContext} cannot be driven by UInt")
18+
}
19+
20+
override def cloneType: this.type = new Type(domain).asInstanceOf[this.type]
21+
22+
override def toPrintable: Printable =
23+
throwException(s"'domain.Type' does not support hardware printing" + this._errorContext)
24+
25+
private[chisel3] def width: Width = UnknownWidth
26+
27+
addDomain(domain)
28+
29+
}
30+
31+
object Type {
32+
33+
def apply(domain: Domain) = new Type(domain)
34+
35+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3
4+
5+
import chisel3.internal.Builder
6+
7+
package object domain {
8+
9+
def addDomain(domain: Domain) = {
10+
Builder.domains += domain
11+
}
12+
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package chisel3.domains
4+
5+
import chisel3.domain.{Domain, Field}
6+
import chisel3.experimental.UnlocatableSourceInfo
7+
8+
object ClockDomain extends Domain()(sourceInfo = UnlocatableSourceInfo) {
9+
10+
override def fields: Seq[(String, Field.Type)] = Seq(
11+
"name" -> Field.String
12+
)
13+
14+
}

core/src/main/scala/chisel3/experimental/IntrinsicModule.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ abstract class IntrinsicModule(intrinsicName: String, val params: Map[String, Pa
2323
// Ports are named in the same way as regular Modules
2424
namePorts()
2525

26-
val firrtlPorts = getModulePorts.map { case port =>
27-
Port(port, port.specifiedDirection, UnlocatableSourceInfo)
26+
val firrtlPorts = getModulePortsAndLocators.map { case (port, _, associations) =>
27+
Port(port, port.specifiedDirection, associations, UnlocatableSourceInfo)
2828
}
2929
val component = DefIntrinsicModule(this, name, firrtlPorts, SpecifiedDirection.Unspecified, params)
3030
_component = Some(component)

core/src/main/scala/chisel3/experimental/hierarchy/core/Instance.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,14 @@ object Instance extends SourceInfoDoc {
133133
require(!_closed, s"Can't generate $desiredName module more than once")
134134
evaluateAtModuleBodyEnd()
135135
_closed = true
136-
val firrtlPorts = importedDefinition.proto.getModulePortsAndLocators.map { case (port, sourceInfo) =>
137-
Port(port, port.specifiedDirection, sourceInfo): @nowarn // Deprecated code allowed for internal use
136+
val firrtlPorts = importedDefinition.proto.getModulePortsAndLocators.map {
137+
case (port, sourceInfo, associations) =>
138+
Port(
139+
port,
140+
port.specifiedDirection,
141+
associations,
142+
sourceInfo
143+
): @nowarn // Deprecated code allowed for internal use
138144
}
139145
val component =
140146
DefBlackBox(

0 commit comments

Comments
 (0)