-
Notifications
You must be signed in to change notification settings - Fork 642
[core] Add initial domain support #5041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
ce1f528
to
74f1910
Compare
Extend the allowed binary incompatibility for more problems in `chisel3.internal.firrtl.ir*` and the same set of problems in `firrtl.ir*`. This is in support of allowing breakages that are necessary to represent domain associations. Signed-off-by: Schuyler Eldridge <[email protected]>
74f1910
to
e40332d
Compare
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]>
e40332d
to
92af846
Compare
abstract class Domain()(implicit val sourceInfo: SourceInfo) { self: Singleton => | ||
|
||
// The name that will be used when generating FIRRTL. | ||
private[chisel3] def name: String = simpleClassName(this.getClass()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private[chisel3] def name: String = simpleClassName(this.getClass()) | |
private[chisel3] def name: String = simpleClassName(this.getClass) |
Nit but we typically call .getClass
without ()
.
protected[chisel3] def getAssociations: scala.collection.immutable.Map[Data, LinkedHashSet[Data]] = | ||
_associations.toMap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really needed or can we just use _associations
?
Builder.error(s"""Unable to associate port '$port' to domains '${allDomains.mkString( | ||
", " | ||
)}' because the port does not exist in this module""")(si) | ||
println(getModulePorts) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
println(getModulePorts) |
stray println
Builder.error(s"""Unable to associate port '$port' to domains '${allDomains.mkString( | ||
", " | ||
)}' because the port does not exist in this module""")(si) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting formatted weirdly, can you massage it a bit, e.g. assign the result of allDomains.mkString
to a val.
private def legalize(name: String): String = { | ||
name match { | ||
// If the name starts with a digit, then escape it with backticks. | ||
case _ if name.head.isDigit => s"`$name`" | ||
case _ => name | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change feels pointless but also is fine
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])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(port, info, _associations.get(port).map(_.toSeq).getOrElse(Seq.empty[Data])) | |
(port, info, _associations.get(port).fold(Seq.empty[Data])(_.toSeq) |
I personally have taken to .fold(default)(f)
instead of .map(f).getOrElse(default)
but I'll defer to you on which you think is better.
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 = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we've often used this T, T*
as a trick to ensure one or more, but it makes certain things really awkward, e.g. trying to work with a Seq, you have to do:
associate(port, myDomains(0), myDomains.tail: _*)
I think it would be better to overload with:
final def associate(port: Data, domain: Data)(implicit si: SourceInfo): Unit = associate(port, Seq(domain))
final def associate(port: Data, domains: Seq[Data])(implicit si: SourceInfo): Unit = ...
Or just have a single version with varags and accept it's a runtime error if called with no domains?
Or I guess you could overload with
final def associate(port: Data, domain: Data, domains: Data*)(implicit si: SourceInfo): Unit = associate(port, Seq(domain) ++ domains)
final def associate(port: Data, domains: Seq[Data])(implicit si: SourceInfo): Unit = ...
/** A [[Data]] that is used to communicate information of a specific domain | ||
* kind. | ||
*/ | ||
final class Type private (val domain: Domain) extends Element { self => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does a domain.Type
really need to be an Element or Data at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They do need to be ports, so I think it would either be changing the type that IO
accepts or adding a new IO creation method just for domain.Type
. Either of these is doable.
The more critical thing would be that I expect libraries that assume everything in Chisel can be shoved into a Wire
, like diplomacy, will want to put domain.Type
into a wire. We might be able to avoid this with changes to libraries so that they don't use a single Wire
. (This is related to what I was talking to you offline about assuming everything can go into a Bundle
is making things hard.) WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, then I think Element
is right. If these need to be ports and wired through then I think they run into the same needs as other things like Properties
. As in the larger conversation about Bundles
, maybe there's a better way out there but there has to be some way to compose these things together and Bundle
(well Record
) remains the only existing avenue.
val A = IO(Input(domain.Type(ClockDomain))) | ||
val B = IO(Input(domain.Type(PowerDomain))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels a bit inconsistent with the rest of Chisel, what about:
val A = IO(Input(domain.Type(ClockDomain))) | |
val B = IO(Input(domain.Type(PowerDomain))) | |
val A = IO(Input(ClockDomain())) | |
val B = IO(Input(PowerDomain())) |
or perhaps
val A = IO(Input(domain.Type(ClockDomain))) | |
val B = IO(Input(domain.Type(PowerDomain))) | |
val A = IO(Input(ClockDomain.Type())) | |
val B = IO(Input(PowerDomain.Type())) |
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.
Release Notes
Add initial support for creating domains. These are intended to model things like clock, reset, and power domains and their associations to ports in the design.