Skip to content
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

Implement asTypeOf, refactor internal APIs #450

Merged
merged 4 commits into from
Feb 15, 2017
Merged

Implement asTypeOf, refactor internal APIs #450

merged 4 commits into from
Feb 15, 2017

Conversation

ducky64
Copy link
Contributor

@ducky64 ducky64 commented Jan 24, 2017

Several refactor changes that shouldn't affect non-nonsensical Chisel:

  • Implement asTypeOf (resolution for Make reinterpret cast conversions (fromBits / asUInt / etc) consistent #433)
  • fromBits currently untouched. Will be chisel3-deprecated if possible as a future PR.
  • Refactor code that needs to create a super-type of several types into cloneSupertype (eliminates the premise of Is there a reason we do an explicit Mux compatibility check? #446)
    • This should be the only thing that changes externally visible API, in that the checks are now more consistent. oneHotMux now checks against inconsistent input types.
  • Split out Mux (raised in Is there a reason we do an explicit Mux compatibility check? #446), and simply using above
  • Simplify Vec construction using above
  • Add a typeEquivalent internal API. This and cloneSupertype eliminates the need for typesCompatible, which is inexplicably a Mux operation.
  • Move cloneTypeWidth from Data to Bits. It used to silently drop the width parameter when called on any non-Bits, which is just sketchy. This makes uses of it explicit and always correct, minus the Bool case.
    • Eventually want to get rid of cloneTypeWidth. The only stragglers are Bits.pad (which can instead create a new UInt/etc from scratch) and Reg (which clears widths behind the scenes for you). Not sure how to address the Reg case.
  • Deprecate flatten, hopefully will remove it eventually using more local operations. The stragglers are mainly Bindings directionality checks, which can be made more local with a resolution to Consolidate directionality data #440.

Originally the intention was to remove fromBits and the less clean APIs that it relied on (like flatten), but many more yaks were shaved. flatten hasn't been removed yet, but should be possible in the near future,

@ducky64 ducky64 changed the title Implement asTypeOf, refactor some other APIs Implement asTypeOf, refactor internal APIs Jan 24, 2017
@ducky64
Copy link
Contributor Author

ducky64 commented Feb 1, 2017

Aggregate.getElements now public.
Data.flatten is still private, since I don't think it's a good Data-level API or is well named (since it returns Element). It might make sense as a utils function or something.

assert( DataMirror.widthOf(truncate).get == 3 )
assert( truncate === 3.U )
assert( DataMirror.widthOf(expand).get == 3 )
assert( expand === 1.U )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why DataMirror.widthOf instead of just .widthOption or .getWidth, also, why does DataMirror.widthOf exist? @sdtwigg

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think DataMirror provides a more reflection-like API for reflection-like operations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your opinion, in user Chisel code should people use DataMirror over .getWidth?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a good argument for an explicit reflection-like API, especially since there are subtleties with width (inferred width doesn't get computed until after Chisel).

But in any case we should standardize on one, and deprecate the other.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, a discussion for a different PR I think

@@ -15,26 +15,22 @@ import chisel3.internal.sourceinfo._
* of) other Data objects.
*/
sealed abstract class Aggregate extends Data {
private[core] def cloneTypeWidth(width: Width): this.type = cloneType
private[core] def width: Width = flatten.map(_.width).reduce(_ + _)
private[core] def getElements: Seq[Data]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed at the Chisel meeting today, getElements could be public, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be reviewing an outdated version, getElements is public...

@@ -15,26 +15,22 @@ import chisel3.internal.sourceinfo._
* of) other Data objects.
*/
sealed abstract class Aggregate extends Data {
private[core] def cloneTypeWidth(width: Width): this.type = cloneType
private[core] def width: Width = flatten.map(_.width).reduce(_ + _)
def getElements: Seq[Data]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScalaDoc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, will do.

private[chisel3] lazy val flatten = elements.toIndexedSeq.flatMap(_._2.flatten)
private[core] override def typeEquivalent(that: Data): Boolean = that match {
case that: Record =>
this.getClass == that.getClass &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually what we want? Bulk connect works on things that are not the same class but have the same elements

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's potential debate to be had here. I think a stricter check makes sense, since I think there's an argument to be made for type equality having meaning.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize in doAggregateMux we are currently requiring that the classes be the same so yeah, I agree with keeping this strict. It is interesting that you can't create a Mux between two otherwise identical anonymous Bundles but you can bulk connect them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Mux they kind of have to be the same class, because you need to pick one as the return type. The least arbitrary thing to do is to pick one but require it be the same as the other.

For connections, there is a debate to be had, but relaxing it later is always easier than imposing a new restriction.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they should require the same class. I can't currently think of a use case where you want to create the same Record in everything but class. For library-like interfaces I think you would want to end up using the library's Record constructor, rather than trying to create your own record with the same elements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aye, it all makes sense now!

@@ -390,6 +392,9 @@ abstract trait Num[T <: Data] {
sealed class UInt private[core] (width: Width, lit: Option[ULit] = None)
extends Bits(width, lit) with Num[UInt] {

private[core] override def typeEquivalent(that: Data): Boolean =
that.isInstanceOf[UInt] && this.width == that.width // TODO: should this be true for unspecified widths?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think it should be true for unspecified widths

private[chisel3] lazy val flatten: IndexedSeq[Bits] =
(0 until length).flatMap(i => this.apply(i).flatten)
override def getElements: Seq[Data] =
(0 until length).map(apply(_))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScalaDoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's a reason to re-define the ScalaDoc in override functions in subclasses.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough

})
res
private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
this := that.asUInt
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scala style is to not use procedure syntax: http://docs.scala-lang.org/style/declarations

ie. ): Unit = {


def do_asTypeOf[T <: Data](that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
val thatCloned = Wire(that.chiselCloneType)
thatCloned.connectFromBits(asUInt())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just my opinion but I generally prefer to use this. when invoking methods on the object at hand. That asUInt() just looks like some magical functional call rather than calling something on this


/** Assigns this node from Bits type. Internal implementation for asTypeOf.
*/
private[core] def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return type

val ret = Wire(this.cloneType)
ret := that
ret.asInstanceOf[this.type]
private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is same comment as the previous one about procedure syntax, I think there are a few of these in this PR

@ducky64
Copy link
Contributor Author

ducky64 commented Feb 15, 2017

Everything else fixed. More discussion on role if type in typeEquivalent may be necessary

@jackkoenig
Copy link
Contributor

There's a conflict in Bits.scala, think you can resolve it?

@ducky64
Copy link
Contributor Author

ducky64 commented Feb 15, 2017

Conflict fixed.

CloneSupertype now works for fixed point (requiring the binary point to be the same) and parts of Analog have been updated to fit the new API.

Merging as soon as tests go green...

@ducky64 ducky64 merged commit 375e2b6 into master Feb 15, 2017
@ducky64 ducky64 deleted the nukeBits branch February 15, 2017 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants