-
Notifications
You must be signed in to change notification settings - Fork 615
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
Allow a counter to be instantiated using a Scala range #1515
Conversation
86e9a12
to
d83f54e
Compare
d83f54e
to
f04b177
Compare
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 super cool and I love being able to create Counters from Ranges, thanks!
A couple of issues I highlighted in a comment:
- I think we should keep the Verilog the same for the simple case
0 until power-of-2
- In at least that case, the width of the register seems to be 1 bigger than it needs to be
val wrap = value === r.last.U | ||
|
||
when (wrap) { | ||
value := r.start.U |
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 the special case can be applied by sticking an if (!(isPow2(r.end) && isPow2(r.step)))
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.
Thanks. I ended up using something very similar to that conditional, but had to also check that the range starts at zero.
@jackkoenig @aswaterman Please re-review when you get a chance. I'm happy to keep tweaking this until you guys are happy 😸 |
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 can confirm the code gen for 0 until power-of-2 case is resolve, thank you for that! This LGTM, some suggestions for improvement but they're not necessary for this PR. Thanks!
def apply(r: Range, cond: Bool = true.B): (UInt, Bool) = { | ||
val c = new Counter(r) | ||
val wrap = WireInit(false.B) | ||
when (cond) { wrap := c.inc() } | ||
(c.value, wrap) |
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 a minor API question, but the range API is a little inconsistent with the old API, if you want an enable its:
Counter(0 until 16, en)
// vs.
Counter(en, 16)
I won't contest that maybe it's the existing API that's awkward, but we probably ought to be consistent 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.
@jackkoenig Thanks for your thoughts 🤔
Unfortunately, flipping the order of the params would make having default values for the enable
param more awkward. IMHO, since you can't construct a counter without a range value (i.e. what good is a counter with an enable
and no range?), it makes sense that this is the first parameter.
My vote would be to deprecate the old API. That way users could have:
Counter(10)
Counter(10, en)
Counter(0 to 10)
Counter(0 to 10, en)
I'm happy to open a new PR to discuss?
@chick or something with admin rights, can you check why the CI isn't reporting? |
@nullobject the test failure may be a real one, the tests that failed use |
bedb084
to
b0a426a
Compare
@jackkoenig Fixed. It was due to a counter being instantiated with I have update the legacy constructor to always create a non-empty range, and added an assertion to ensure that counters can never be instantiated with an empty range. I don't think supporting empty ranges makes much sense, because how can you ever count zero elements? |
require(r.start >= 0 && r.end >= 0, s"Counter range must be positive, got: $r") | ||
|
||
private lazy val delta = math.abs(r.step) | ||
private lazy val width = math.max(log2Up(r.last + 1), log2Up(r.head + 1)) |
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.
Not a problem, but just FYI: abs
and max
are defined on the various integral types, so you can write e.g. r.step.abs
or foo max bar
.
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.
Thanks 😄
I'm still learning how to write idomatic Scala.
I think updating the legacy constructor to support |
0fc6c93
to
a70d3fa
Compare
Co-authored-by: Jack Koenig <jack.koenig3@gmail.com>
We only need to explicitly wrap counters that don't start at zero, or end on a power of two. Otherwise we just let the counter overflow naturally to avoid wasting an extra mux.
a70d3fa
to
bded72a
Compare
@nullobject do you care how this is merged? Do you want it with a merge commit or is a squash-and-merge fine? Also sorry for the delay, somehow I missed the last few emails about this PR. |
@jackkoenig Not really, whatever you guys normally do. Happy to squash it all into one commit if you prefer? |
@nullobject since we require PRs to be up-to-date to merge, we usually usually let the trust bot @Mergify.io queue them up, merging master, then squash-and-merging. I'll get that started now. Thanks! |
@jackkoenig Fantastic. Thanks for persisting with my PR. I'm happy to have made my first contribution to Chisel 🙌 |
@nullobject Thank you so much! It was a pleasure and an excellent contribution! |
This PR adds the ability for a counter to be instantiated using a Scala range.
The original API has been preserved, but the counter now works internally with a range. Using a range to configure the counter allows us to do interesting things.
Counting upwards:
Counting downwards:
Counting upwards by twos:
It also allows an optional condition attribute (similar to the existing API):
I'm fairly new to Chisel, but I think that having the condition as the second parameter feels more consistent with the rest of the Chisel API.
I'm happy to scale this PR back if you think it's changing too much at once, but I'm keen to get some feedback on the overall goal. Thoughts?
Type of change: feature request
Impact: API addition (no impact on existing code)
Development Phase: proposal
Release Notes
Allow a counter to be instantiated using a Scala range