Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions core/src/main/scala/chisel3/BlackBox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ package experimental {
// Ports are named in the same way as regular Modules
namePorts()

val firrtlPorts = getModulePorts.map { case port =>
Port(port, port.specifiedDirection, UnlocatableSourceInfo)
val firrtlPorts = getModulePortsAndLocators.map { case (port, _, associations) =>
Port(port, port.specifiedDirection, associations, UnlocatableSourceInfo)
}
val component = DefBlackBox(this, name, firrtlPorts, SpecifiedDirection.Unspecified, params, getKnownLayers)
_component = Some(component)
Expand Down Expand Up @@ -217,8 +217,8 @@ abstract class BlackBox(
port.setRef(ModuleIO(this, _namespace.name(name)), force = true)
}

val firrtlPorts = namedPorts.map { namedPort =>
Port(namedPort._2, namedPort._2.specifiedDirection, UnlocatableSourceInfo)
val firrtlPorts = getModulePortsAndLocators.map { case (port, _, associations) =>
Port(port, port.specifiedDirection, associations, UnlocatableSourceInfo)
}
val component = DefBlackBox(this, name, firrtlPorts, io.specifiedDirection, params, getKnownLayers)
_component = Some(component)
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/chisel3/IO.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package chisel3

import chisel3.domain
import chisel3.internal.{throwException, Builder}
import chisel3.experimental.{noPrefix, requireIsChiselType, SourceInfo}
import chisel3.properties.{Class, Property}
Expand Down
31 changes: 26 additions & 5 deletions core/src/main/scala/chisel3/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -576,16 +576,20 @@ package experimental {

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

private val _associations = new HashMap[Data, LinkedHashSet[Data]]()

// getPorts unfortunately already used for tester compatibility
protected[chisel3] def getModulePorts: Seq[Data] = {
require(_closed, "Can't get ports before module close")
_ports.iterator.collect { case (d: Data, _) => d }.toSeq
}

// gets Ports along with there source locators
private[chisel3] def getModulePortsAndLocators: Seq[(Data, SourceInfo)] = {
private[chisel3] def getModulePortsAndLocators: Seq[(Data, SourceInfo, Seq[Data])] = {
require(_closed, "Can't get ports before module close")
_ports.toSeq
_ports.toSeq.map { case (port, info) =>
(port, info, _associations.get(port).map(_.toSeq).getOrElse(Seq.empty[Data]))
}
}

/** Get IOs that are currently bound to this module.
Expand All @@ -608,6 +612,21 @@ package experimental {

protected def portsSize: Int = _ports.size

/* Associate a port of this module with one or more domains. */
final def associate(port: Data, domain: Data, domains: Data*)(implicit si: SourceInfo): Unit = {
val allDomains = Seq(domain) ++ domains
if (!portsContains(port)) {
Builder.error(s"""Unable to associate port '$port' to domains '${allDomains.mkString(
", "
)}' because the port does not exist in this module""")(si)
return
}
_associations.updateWith(port) {
case Some(acc) => Some(acc ++= allDomains)
case None => Some(LinkedHashSet.empty[Data] ++= allDomains)
}
}

/** Generates the FIRRTL Component (Module or Blackbox) of this Module.
* Also closes the module so no more construction can happen inside.
*/
Expand All @@ -618,7 +637,7 @@ package experimental {
private[chisel3] def initializeInParent(): Unit

private[chisel3] def namePorts(): Unit = {
for ((port, source) <- getModulePortsAndLocators) {
for ((port, source, _) <- getModulePortsAndLocators) {
port._computeName(None) match {
case Some(name) =>
if (_namespace.contains(name)) {
Expand Down Expand Up @@ -882,7 +901,7 @@ package experimental {
private[chisel3] def addSecretIO[A <: Data](iodef: A)(implicit sourceInfo: SourceInfo): A = {
val name = iodef._computeName(None).getOrElse("secret")
iodef.setRef(ModuleIO(this, _namespace.name(name)))
val newPort = new Port(iodef, iodef.specifiedDirection, sourceInfo)
val newPort = new Port(iodef, iodef.specifiedDirection, Seq.empty, sourceInfo)
if (_closed) {
_component.get.secretPorts += newPort
} else secretPorts += newPort
Expand All @@ -905,7 +924,9 @@ package experimental {
* TODO(twigg): Specifically walk the Data definition to call out which nodes
* are problematic.
*/
protected def IO[T <: Data](iodef: => T)(implicit sourceInfo: SourceInfo): T = {
protected def IO[T <: Data](iodef: => T)(
implicit sourceInfo: SourceInfo
): T = {
chisel3.IO.apply(iodef)
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/main/scala/chisel3/RawModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ abstract class RawModule extends BaseModule {
private var _firrtlPorts: Option[Seq[Port]] = None

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

val firrtlPorts = getModulePortsAndLocators.map { case (port, sourceInfo) =>
Port(port, port.specifiedDirection, sourceInfo)
val firrtlPorts = getModulePortsAndLocators.map { case (port, sourceInfo, associations) =>
Port(port, port.specifiedDirection, associations, sourceInfo)
}
_firrtlPorts = Some(firrtlPorts)

Expand Down
20 changes: 20 additions & 0 deletions core/src/main/scala/chisel3/domain/Domain.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.domain

import chisel3.experimental.SourceInfo
import chisel3.util.simpleClassName

object Field {
sealed trait Type

object String extends Type
}

abstract class Domain()(implicit val sourceInfo: SourceInfo) { self: Singleton =>

private[chisel3] def name: String = simpleClassName(this.getClass())

def fields: Seq[(String, Field.Type)] = Seq.empty

}
35 changes: 35 additions & 0 deletions core/src/main/scala/chisel3/domain/Type.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.domain

import chisel3.{fromIntToLiteral, Data, Element, Printable, UInt, UnknownWidth, Width}
import chisel3.experimental.SourceInfo
import chisel3.internal.{throwException, Builder}

final class Type private (val domain: Domain) extends Element { self =>

private[chisel3] def _asUIntImpl(first: Boolean)(implicit sourceInfo: SourceInfo): chisel3.UInt = {
Builder.error(s"${this._localErrorContext} does not support .asUInt.")
0.U
}

override protected def _fromUInt(that: UInt)(implicit sourceInfo: SourceInfo): Data = {
Builder.exception(s"${this._localErrorContext} cannot be driven by UInt")
}

override def cloneType: this.type = new Type(domain).asInstanceOf[this.type]

override def toPrintable: Printable =
throwException(s"'domain.Type' does not support hardware printing" + this._errorContext)

private[chisel3] def width: Width = UnknownWidth

addDomain(domain)

}

object Type {

def apply(domain: Domain) = new Type(domain)

}
13 changes: 13 additions & 0 deletions core/src/main/scala/chisel3/domain/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3

import chisel3.internal.Builder

package object domain {

def addDomain(domain: Domain) = {
Builder.domains += domain
}

}
14 changes: 14 additions & 0 deletions core/src/main/scala/chisel3/domains/ClockDomain.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0

package chisel3.domains

import chisel3.domain.{Domain, Field}
import chisel3.experimental.UnlocatableSourceInfo

object ClockDomain extends Domain()(sourceInfo = UnlocatableSourceInfo) {

override def fields: Seq[(String, Field.Type)] = Seq(
"name_pattern" -> Field.String
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ abstract class IntrinsicModule(intrinsicName: String, val params: Map[String, Pa
// Ports are named in the same way as regular Modules
namePorts()

val firrtlPorts = getModulePorts.map { case port =>
Port(port, port.specifiedDirection, UnlocatableSourceInfo)
val firrtlPorts = getModulePortsAndLocators.map { case (port, _, associations) =>
Port(port, port.specifiedDirection, associations, UnlocatableSourceInfo)
}
val component = DefIntrinsicModule(this, name, firrtlPorts, SpecifiedDirection.Unspecified, params)
_component = Some(component)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,14 @@ object Instance extends SourceInfoDoc {
require(!_closed, s"Can't generate $desiredName module more than once")
evaluateAtModuleBodyEnd()
_closed = true
val firrtlPorts = importedDefinition.proto.getModulePortsAndLocators.map { case (port, sourceInfo) =>
Port(port, port.specifiedDirection, sourceInfo): @nowarn // Deprecated code allowed for internal use
val firrtlPorts = importedDefinition.proto.getModulePortsAndLocators.map {
case (port, sourceInfo, associations) =>
Port(
port,
port.specifiedDirection,
associations,
sourceInfo
): @nowarn // Deprecated code allowed for internal use
}
val component =
DefBlackBox(
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/scala/chisel3/internal/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ private[chisel3] class DynamicContext(
val annotations = ArrayBuffer[() => Seq[Annotation]]()
val layers = mutable.LinkedHashSet[layer.Layer]()
val options = mutable.LinkedHashSet[choice.Case]()
val domains = mutable.LinkedHashSet[domain.Domain]()
var currentModule: Option[BaseModule] = None

// Views that do not correspond to a single ReferenceTarget and thus require renaming
Expand Down Expand Up @@ -602,6 +603,7 @@ private[chisel3] object Builder extends LazyLogging {

def layers: mutable.LinkedHashSet[layer.Layer] = dynamicContext.layers
def options: mutable.LinkedHashSet[choice.Case] = dynamicContext.options
def domains: mutable.LinkedHashSet[domain.Domain] = dynamicContext.domains

def contextCache: BuilderContextCache = dynamicContext.contextCache

Expand Down Expand Up @@ -1122,7 +1124,8 @@ private[chisel3] object Builder extends LazyLogging {
makeViewRenameMap(circuitName = components.last.name),
typeAliases,
layerAdjacencyList(layer.Layer.Root).map(foldLayers).toSeq,
optionDefs
optionDefs,
domains.toSeq.map(d => Domain(d.sourceInfo, d.name))
)
(ElaboratedCircuit(circuit, dynamicContext.annotationSeq.toSeq), mod)
}
Expand Down
9 changes: 8 additions & 1 deletion core/src/main/scala/chisel3/internal/firrtl/Converter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ private[chisel3] object Converter {
extractType(t._elements.head._2, childClearDir, info, checkProbe, true, typeAliases)
}
case t: Property[_] => t.getPropertyType
case t: domain.Type => fir.DomainType(t.domain.name)
}

def convert(name: String, param: Param): fir.Param = param match {
Expand Down Expand Up @@ -441,7 +442,13 @@ private[chisel3] object Converter {
case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip => false
}
val tpe = extractType(port.id, clearDir, port.sourceInfo, true, true, typeAliases)
fir.Port(convert(port.sourceInfo), getRef(port.id, port.sourceInfo).name, dir, tpe)
fir.Port(
convert(port.sourceInfo),
getRef(port.id, port.sourceInfo).name,
dir,
tpe,
port.associations.map(getRef(_, UnlocatableSourceInfo).name)
)
}

def convert(component: Component, typeAliases: Seq[String]): fir.DefModule = component match {
Expand Down
10 changes: 8 additions & 2 deletions core/src/main/scala/chisel3/internal/firrtl/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,11 @@ private[chisel3] object ir {
chiselLayer: layer.Layer
)

final case class Domain(
sourceInfo: SourceInfo,
name: String
)

class LayerBlock(val sourceInfo: SourceInfo, val layer: chisel3.layer.Layer) extends Command {
val region = new Block(sourceInfo)
}
Expand All @@ -498,7 +503,7 @@ private[chisel3] object ir {
case class DefOption(sourceInfo: SourceInfo, name: String, cases: Seq[DefOptionCase])
case class DefOptionCase(sourceInfo: SourceInfo, name: String)

case class Port(id: Data, dir: SpecifiedDirection, sourceInfo: SourceInfo)
case class Port(id: Data, dir: SpecifiedDirection, associations: Seq[Data], sourceInfo: SourceInfo)

case class Printf(
id: printf.Printf,
Expand Down Expand Up @@ -606,7 +611,8 @@ private[chisel3] object ir {
renames: RenameMap,
typeAliases: Seq[DefTypeAlias],
layers: Seq[Layer],
options: Seq[DefOption]
options: Seq[DefOption],
domains: Seq[Domain]
) {
def firrtlAnnotations: Iterable[Annotation] = annotations.flatMap(_().flatMap(_.update(renames)))
}
Expand Down
28 changes: 28 additions & 0 deletions core/src/main/scala/chisel3/internal/firrtl/Serializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ private[chisel3] object Serializer {
case t: Property[_] =>
// TODO can we not use FIRRTL types here?
b ++= fir.Serializer.serialize(t.getPropertyType)
case t: domain.Type => b ++= "Domain of "; b ++= t.domain.name;
}

private def serialize(name: String, param: Param)(implicit b: StringBuilder): Unit = param match {
Expand Down Expand Up @@ -561,6 +562,14 @@ private[chisel3] object Serializer {
b ++= legalize(getRef(port.id, port.sourceInfo).name)
b ++= " : "
val tpe = serializeType(port.id, clearDir, port.sourceInfo, true, true, typeAliases)
if (port.associations.nonEmpty) {
b ++= " domains ["
port.associations.zipWithIndex.foreach { case (assoc, i) =>
if (i > 0) b ++= ", "
b ++= legalize(getRef(assoc, UnlocatableSourceInfo).name)
}
b ++= "]"
}
serialize(port.sourceInfo)
}

Expand Down Expand Up @@ -665,6 +674,23 @@ private[chisel3] object Serializer {
// serialize(ta.sourceInfo) TODO: Uncomment once firtool accepts infos for type aliases
}

private def serialize(domain: Domain)(implicit b: StringBuilder, indent: Int): Unit = {
newLineAndIndent()
b ++= "domain "
b ++= domain.name
b ++= " :"
}

private def serializeDomains(domains: Seq[Domain])(implicit indent: Int): Iterator[String] = {
if (domains.isEmpty)
return Iterator.empty

implicit val b = new StringBuilder
domains.foreach(serialize)
newLineNoIndent()
Iterator(b.toString)
}

// TODO make Annotation serialization lazy
private def serialize(circuit: Circuit, annotations: Seq[Annotation]): Iterator[String] = {
implicit val indent: Int = 0
Expand Down Expand Up @@ -699,12 +725,14 @@ private[chisel3] object Serializer {
Iterator(b.toString)
} else Iterator.empty
val layers = serialize(circuit.layers)(indent + 1)
val domains = serializeDomains(circuit.domains)(indent + 1)
// TODO what is typeAliases for? Should it be a Set?
val typeAliasesSeq: Seq[String] = circuit.typeAliases.map(_.name)
prelude ++
options ++
typeAliases ++
layers ++
domains ++
circuit.components.iterator.zipWithIndex.flatMap { case (m, i) =>
val newline = Iterator(if (i == 0) s"$NewLine" else s"${NewLine}${NewLine}")
newline ++ serialize(m, typeAliasesSeq)(indent + 1)
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/chisel3/properties/Class.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ class Class extends BaseModule {
}

// Create IR Ports and set the firrtlPorts variable.
val ports = getModulePortsAndLocators.map { case (port, sourceInfo) =>
Port(port, port.specifiedDirection, sourceInfo)
val ports = getModulePortsAndLocators.map { case (port, sourceInfo, _) =>
Port(port, port.specifiedDirection, Seq.empty, sourceInfo)
}

// No more commands.
Expand Down
Loading
Loading