Operator precedence of `<=` misleading when using `if-then`
See original GitHub issueIn Python <=
has higher precedence than not
, or
, and
, if-then
, and lambda
. In cocotb <=
is reused as an assignment operator, which leads to some highly surprising behavior when compared to the “normal” assignment operator =
.
Example | Expected | Actual | ||
---|---|---|---|---|
1 | a <= b or c |
a <= (b or c) |
(a <= b) or c |
Edit: Mitigation implemented, see below |
2 | a <= b and c |
a <= (b and c) |
(a <= b) and c |
Edit: Mitigation implemented, see below |
3 | a <= b if c else d |
a <= (b if c else d) |
(a <= b) if c else d |
I recently had my third encounter with this behavior. Although I had seen it twice before, it still took me some time to realize it was an operator precedence issue thanks to the pervasiveness of “normal” assignments.
Partial solution
Edit: this has already been implemented. With a recent version of cocotb only `if-then` is still an issue. Click to expand original text.
To prevent (1) and (2) <=
could return a singleton DontUse
like:
class DontUse:
def __bool__(self):
raise ValueError("Don't use me like this dummy")
DontUse = DontUse()
This would make Python throw the error when trying to evaluate or
and and
. There’s no such workaround available for if-then
AFAIK.
Full solution
I don’t think there’s much we can do. I think using <=
should be deprecated and eventually removed entirely. There’s very little benefit, but it can cause some pretty annoying debug sessions. Assignment on simulator objects should probably replace <=
's current function.
Old | New |
---|---|
dut.a <= b if c else d |
dut.a = b if c else d |
a <= b if c else d |
a.value = b if c else d |
The good news is that there’s a good upgrade path:
- Deprecation warning on
<=
- Hard error in
__le__
- Removal of
__le__
(?)
Workarounds
- Use parentheses:
a <= (b if c else d)
- Use
.value
:a.value = b if c else d
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (5 by maintainers)
Top GitHub Comments
We already implement the partial solution you suggest (as of #766, cocotb 1.2.0):
https://github.com/cocotb/cocotb/blob/fba7b854b00375500552ff8804757f468152b111/cocotb/handle.py#L476-L483
https://github.com/cocotb/cocotb/blob/fba7b854b00375500552ff8804757f468152b111/cocotb/handle.py#L418-L434
Works for me. It’s non-surprising, performant, and solves this issue. It’s slightly annoying that it makes testbenches more verbose, but I 💯% prefer that over the status quo.