-
Notifications
You must be signed in to change notification settings - Fork 603
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
Add recursive Bundle
and generic Data
equality (===)
#2669
Conversation
behavior.of("DontCare") | ||
it should "only be equal to itself" in { | ||
assertTesterPasses { | ||
new EqualityTester(DontCare, DontCare) |
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 two different calls to DontCare
should be equal. That is not what happens in the firrtl
if you did not check in the frontend.
.reduce(_ && _) | ||
} | ||
// This should be matching to (DontCare, DontCare) but the compiler wasn't happy with that | ||
case (_: DontCare.type, _: DontCare.type) => true.B |
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 comparing DontCare should not be possible. We do not want these two versions of code to (silently) have different behavior:
DontCare === DontCare
val a = Wire(UInt(4.W))
val b = Wire(UInt(4.W))
a := DontCare
b := DontCare
a === b
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.
We do not want these two versions of code to (silently) have different behavior
Absolutely agreed, but the behavior of the two actually is the same, both will give true
. Here's a Scastie illustrating the behavior:
import chisel3._
import chisel3.util.Valid
import chisel3.experimental.BundleLiterals._
class Example extends Module {
val out1, out2 = IO(Output(Bool()))
val u1 = WireInit(UInt(8.W), DontCare)
val u2 = WireInit(UInt(8.W), DontCare)
out1 := u1 === u2
val b1 = Valid(UInt(8.W)).Lit(_.bits -> 123.U) // unspecified is implicitly DontCare
val b2 = Valid(UInt(8.W)).Lit(_.bits -> 123.U)
out2 := b1.asUInt === b2.asUInt
}
This gives the following FIRRTL
circuit Example :
module Example :
input clock : Clock
input reset : UInt<1>
output out1 : UInt<1>
output out2 : UInt<1>
wire u1 : UInt<8>
u1 is invalid
wire u2 : UInt<8>
u2 is invalid
node _out1_T = eq(u1, u2)
out1 <= _out1_T
wire _out2_WIRE : UInt<1>
_out2_WIRE is invalid
node _out2_T = cat(_out2_WIRE, UInt<7>("h7b"))
wire _out2_WIRE_1 : UInt<1>
_out2_WIRE_1 is invalid
node _out2_T_1 = cat(_out2_WIRE_1, UInt<7>("h7b"))
node _out2_T_2 = eq(_out2_T, _out2_T_1)
out2 <= _out2_T_2
And the following Verilog:
module Example(
input clock,
input reset,
output out1,
output out2
);
assign out1 = 1'h1; // @[main.scala 13:14]
assign out2 = 1'h1; // @[main.scala 17:21]
endmodule
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'm not sure this is a good thing, but it is consistent.
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.
As annoying as it is, comparing two invalidated wires should return true. A lot of Chisel code intentionally or unintentionally assumes that invalid is zero in certain contexts. This is documented in CIRCT. I would love to change this, but it would be very difficult at this point. I do think defining a new concept of poison and seeing where that goes is tractable.
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 do think defining a new concept of poison and seeing where that goes is tractable.
But beyond the scope of this PR for sure 🙂
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.
The ambiguity around DontCare === 0.U
is why I feel like making them uncomparable by generating an elaboration time error might be the best solution 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.
I agree that the ambiguity is a problem, but is it a better outcome that the following would fail:
val b1 = Valid(UInt(8.W)).Lit(_.bits -> 123.U) // unspecified is implicitly DontCare
val b2 = Valid(UInt(8.W)).Lit(_.bits -> 123.U)
b1 === b2
But this would not?
val b1 = Valid(UInt(8.W)).Lit(_.bits -> 123.U) // unspecified is implicitly DontCare
val b2 = Valid(UInt(8.W)).Lit(_.bits -> 123.U)
WireInit(b1) === WireInit(b2)
…ead of returning false
(cherry picked from commit 67cff82)
(cherry picked from commit 67cff82) Co-authored-by: Jared Barocsi <82000041+jared-barocsi@users.noreply.github.com>
Contributor Checklist
docs/src
?Type of Improvement
API Impact
===
operator toData
typesBackend Code Generation Impact
No impact
Desired Merge Strategy
Squash and merge
Release Notes
Implement recursive
Bundle
andData
equalityBundle
andData
objects to be compared with===
directly, without any additional steps like casting toUInt
Reviewer Checklist (only modified by reviewer)
3.4.x
, [small] API extension:3.5.x
, API modification or big change:3.6.0
)?Enable auto-merge (squash)
, clean up the commit message, and label withPlease Merge
.Create a merge commit
.