-
Notifications
You must be signed in to change notification settings - Fork 602
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
Bundle Literals Framework #820
Conversation
Changes:
|
Added a test |
It appears that we current don't support I've fixed the |
Also, those tests probably don't belong in LiteralExtractorSpec, since they deal more with Bundle literals than literal extractors. |
The aliasing between Chisel |
It might also not be a bad idea to discuss renaming assert because of the pain it's causing with ScalaTest. |
case Some(litArg) => Some(litArg.num) | ||
case _ => None | ||
} | ||
|
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.
Cleaner as
override def litToBigIntOption: Option[BigInt] = litArgOption.map(_.num)
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.
Fixed, thanks!
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 looks ok to me. There is some reasonable name changing like DynamicContext to ChiselContext that creates a lot of diff's but overall looks ok. This PR REQUIRES documentation in the wiki and probably some more tests after that doc is written. I'd suggest at least one more approval before merging
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.
A few comments, questions, suggestions
private[chisel3] def litIsForcedWidth: Option[Boolean] = litArgOption match { | ||
case Some(litArg) => Some(litArg.forcedWidth) | ||
case _ => None | ||
} |
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.
Similar to the above
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.
Fixed
case Some(intVal) if intVal == 0 => Some(false) | ||
case Some(intVal) => throwException(s"Boolean with unexpected literal value $intVal") | ||
case None => None | ||
} |
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.
I think better as something like:
def litToBooleanOption: Option[Boolean] = litToBigIntOption.map { intVal =>
if (intVal == 1) true
else if (intVal == 0) false
else throwException(s"Boolean with unexpected literal value $intVal")
}
or
def litToBooleanOption: Option[Boolean] = litToBigIntOption.map {
case intVal if intVal == 1 => true
case intVal if intVal == 0 => false
case intVal => throwException(s"Boolean with unexpected literal value $intVal")
}
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.
I like option 2 for the (grammatical) parallelism; fixed.
val multiplier = math.pow(2, binaryPoint.get) | ||
Some(intVal.toDouble / multiplier) | ||
case _ => None | ||
} |
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.
I guess across the board I think it's better to leave off the case _ => None
by just using .map
on Options
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.
fixed
def isLit(): Boolean = litArg.isDefined | ||
|
||
// If this is an element literal, returns the LitArg bound to it. | ||
// INTERNAL API, but this isn't protected to allow bundle literal constructors. |
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.
I think this should be a ScalaDoc indicating that this is really an internal API. Does it need to be public or could it be protected if it's accessed by Bundle literal constructors which are methods on children of Bundle right?
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.
Looking into more creative solutions to this.
The basic issue is this:
[error] Access to protected method elementLitArg not permitted because
[error] prefix type chisel3.Bool does not conform to
[error] class MyBundle where the access take place
[error] clone.b -> bVal.elementLitArg.get
though MyBundle is a type of Bundle which is a type of Data, accessing the override elementLitArg defined in Element seems to cause problems.
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.
Fixed, added a protected Aggregate.litArgOfBits
for this purpose, which depends on private[core] Bits.litArgOption
case _ => None | ||
} | ||
@chiselRuntimeDeprecated | ||
@deprecated("litValue deprecated, use litToBigInt or litTo*", "chisel3.2") |
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.
I don't think this should be deprecated. litToBigInt
does the same thing just with a different name so I see no reason to deprecate this for a slight name change. I agree with deprecating litArg
since we generally don't want people accessing the Chisel IR though.
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.
I think litValue
is ambiguous (for example, on FixedPoint you would not get the original value out) and inconsistent with the new API style (litTo[Type]
), and we should encourage one way of doing things, instead of having two equivalent representations (yes, I know Scala does this, and I think they're wrong).
We could also standardize on litValue instead of litToBigInt, though I think the latter is more clear. And the former is not consistent with the other literal extractors we would want (especially for the new testers), like litToBoolean or litToDouble.
@@ -28,8 +28,8 @@ class SwitchContext[T <: Bits](cond: T, whenContext: Option[WhenContext], lits: | |||
def is(v: Iterable[T])(block: => Unit): SwitchContext[T] = { | |||
if (!v.isEmpty) { | |||
val newLits = v.map { w => | |||
require(w.isLit, "is conditions must be literals!") | |||
val value = w.litValue | |||
require(w.litToBigIntOption != None, "is condition must be literal") |
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.
w.litToBigIntOption != None
=> w.litToBigIntOption.isDefined
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.
fixed
Agree with Chick on documentation. From a user perspective that actually might be more interesting to review. |
This shows errors comparing literals
Resolution from today's meeting: don't deprecate litValue, because modifying public APIs is bad. Instead, litToBigInt will be removed to avoid duplication of features. Alternatives explored:
The downside is that |
It seems like any literal naming stability issues would be caused by code in UserModule.scala: // All suggestions are in, force names to every node.
for (id <- getIds) {
id match {
case id: BaseModule => id.forceName(default=id.desiredName, _namespace)
case id => id.forceName(default="_T", _namespace)
}
id._onModuleClose Having that filter by binding type probably names sense (in particular, ignore LitBinding, maybe also PortBinding since Ports need to be user-specified anyways) and should fix this. |
It's my fault for not providing a better test, but this currently does not preserve the non-lit naming behavior of #826. I'll provide a better test |
@@ -62,6 +62,12 @@ sealed abstract class Aggregate extends Data { | |||
} | |||
} | |||
|
|||
override def litOption = ??? // TODO implement me |
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 TODO intended to be resolved in this PR or later?
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 meant to be implemented later. Literal extractors on Bundles would be a new feature.
|
||
requireIsHardware(this, "bits to be indexed") | ||
pushOp(DefPrim(sourceInfo, Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x))) | ||
} |
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.
Just for the historical record:
These are minor constant propagations done on literals. I did some archaeology to understand why they were there in the first place. They date to very early chisel3 7ada20e and appear to be largely to work around bugs in order to get riscv-mini compiling. Most of them have already been removed but a couple seem to have stuck around. I agree they should be removed.
case Some(ElementLitBinding(litArg)) => litArg | ||
case Some(BundleLitBinding(litMap)) => litMap.get(this) match { | ||
case Some(litArg) => litArg | ||
case _ => throwException(s"internal error: DontCare should be caught before connect") |
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.
I get that this is an internal (and thus unexpected) error, but is it wise to specifically mention "connect" here?
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.
Fair, changed it to say ref instead.
Yes I agree. And in fact then we can do much more than #826 did because we could possibly prevent Bundle types from impacting temporary name suffixes as well! I'm okay with not doing that whole hog in this PR, just so long as we preserve the behavior from #826 |
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.
UserModule forceName is now filtered by binding type. BlackBoxes will not forceName at all (it probably doesn't make sense to have temporaries on BlackBoxes anyways).
@@ -62,6 +62,12 @@ sealed abstract class Aggregate extends Data { | |||
} | |||
} | |||
|
|||
override def litOption = ??? // TODO implement me |
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 meant to be implemented later. Literal extractors on Bundles would be a new feature.
case Some(ElementLitBinding(litArg)) => litArg | ||
case Some(BundleLitBinding(litMap)) => litMap.get(this) match { | ||
case Some(litArg) => litArg | ||
case _ => throwException(s"internal error: DontCare should be caught before connect") |
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.
Fair, changed it to say ref instead.
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 looks great! Thank you for all of your hard work on this
Unfortunately, commit 46f0aa3 / 93eedef breaks SimpleTBSpec tests in dsptools: STARTING test_run_dir/SimpleTB.SimpleTBSpec1077962831/VSimpleLitModule
[info] [0.002] SEED 1531158343599
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:347)
at scala.None$.get(Option.scala:345)
at chisel3.internal.HasId$class.getRef(Builder.scala:114)
at chisel3.core.Data.getRef(Data.scala:201)
at chisel3.internal.firrtl.Node.fullName(IR.scala:56)
at chisel3.internal.firrtl.Slot.fullName(IR.scala:105)
at chisel3.internal.HasId$class.instanceName(Builder.scala:119)
at chisel3.core.Data.instanceName(Data.scala:201)
at dsptools.DspTesterUtilities$.getName(DspTesterUtilities.scala:57)
at dsptools.DspTester.expect(DspTester.scala:301)
at dsptools.DspTester.expect(DspTester.scala:248)
at dsptools.DspTester.expect(DspTester.scala:246)
at SimpleTB.EasyPeekPoke$class.check(SimpleTBwGenTypeOption.scala:54)
at SimpleTB.PassLitTester.check(SimpleTBwGenTypeOption.scala:259)
at SimpleTB.EasyPeekPoke$class.checkP(SimpleTBwGenTypeOption.scala:34)
at SimpleTB.PassLitTester.checkP(SimpleTBwGenTypeOption.scala:259)
at SimpleTB.PassLitTester$$anonfun$8.apply(SimpleTBwGenTypeOption.scala:271)
at SimpleTB.PassLitTester$$anonfun$8.apply(SimpleTBwGenTypeOption.scala:271)
at scala.collection.Iterator$class.foreach(Iterator.scala:891)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1334)
at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
at scala.collection.AbstractIterable.foreach(Iterable.scala:54)
at SimpleTB.PassLitTester.<init>(SimpleTBwGenTypeOption.scala:271)
at SimpleTB.SimpleTBSpec$$anonfun$17$$anonfun$apply$6.apply(SimpleTBwGenTypeOption.scala:375)
at SimpleTB.SimpleTBSpec$$anonfun$17$$anonfun$apply$6.apply(SimpleTBwGenTypeOption.scala:374)
at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1$$anonfun$apply$mcZ$sp$2.apply$mcZ$sp(Driver.scala:65)
at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1$$anonfun$apply$mcZ$sp$2.apply(Driver.scala:64)
at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1$$anonfun$apply$mcZ$sp$2.apply(Driver.scala:64)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1.apply$mcZ$sp(Driver.scala:63)
at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1.apply(Driver.scala:39)
at chisel3.iotesters.Driver$$anonfun$execute$1$$anonfun$apply$mcZ$sp$1.apply(Driver.scala:39)
at logger.Logger$$anonfun$makeScope$1.apply(Logger.scala:129)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
at logger.Logger$.makeScope(Logger.scala:127)
at chisel3.iotesters.Driver$$anonfun$execute$1.apply$mcZ$sp(Driver.scala:39)
at chisel3.iotesters.Driver$$anonfun$execute$1.apply(Driver.scala:39)
at chisel3.iotesters.Driver$$anonfun$execute$1.apply(Driver.scala:39)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
at chisel3.iotesters.Driver$.execute(Driver.scala:38)
at dsptools.Driver$$anonfun$execute$1.apply$mcZ$sp(Driver.scala:29)
at dsptools.Driver$$anonfun$execute$1.apply(Driver.scala:26)
at dsptools.Driver$$anonfun$execute$1.apply(Driver.scala:26)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)
at dsptools.Driver$.execute(Driver.scala:26)
at SimpleTB.SimpleTBSpec$$anonfun$17.apply(SimpleTBwGenTypeOption.scala:374)
at SimpleTB.SimpleTBSpec$$anonfun$17.apply(SimpleTBwGenTypeOption.scala:368)
... due to the fact that |
I also found that 95f1e17 breaks connecting the result of |
Related issue: #805
Type of change: other enhancement
Impact: API addition, API deprecation
Development Phase: proposed implementation
Release Notes
[internal] ids are now persistent through runs, necessary to allow Bundle literals outside a Builder context (otherwise, a new IdGen is created for each element, and the ids alias).hashcode
andequals
reverted to the Java Object defaults, which allows Data created outside a Builder context to be Map-indexableOther notes: