migen icon indicating copy to clipboard operation
migen copied to clipboard

Python logical operator 'and' silently dropped

Open tdaede opened this issue 7 years ago • 18 comments

The following migen snippet:

               If((self.addr == 0x18a) and (self.joy_enabled == 1),

produces the following Verilog:

                if ((addr_1 == 9'd394)) begin

tdaede avatar Sep 27 '18 11:09 tdaede

Yes, you cannot use and - it cannot be redefined in Python.

sbourdeauducq avatar Sep 27 '18 12:09 sbourdeauducq

Is there any way to make it a hard error?

tdaede avatar Sep 27 '18 12:09 tdaede

Actually it should raise TypeError("Attempted to convert Migen value to boolean") (see fhdl/structure.py). Can you find out why that does not happen?

sbourdeauducq avatar Sep 27 '18 14:09 sbourdeauducq

@sbourdeauducq Because of the special case in __bool__:

        # Special case: Constants and Signals are part of a set or used as
        # dictionary keys, and Python needs to check for equality.
        if isinstance(self, _Operator) and self.op == "==":
            a, b = self.operands
            if isinstance(a, Constant) and isinstance(b, Constant):
                return a.value == b.value
            if isinstance(a, Signal) and isinstance(b, Signal):
                return a is b
            if (isinstance(a, Constant) and isinstance(b, Signal)
                    or isinstance(a, Signal) and isinstance(b, Constant)):
                return False

I don't understand why it lives in __bool__ though.

whitequark avatar Nov 10 '18 19:11 whitequark

Where should it be instead?

sbourdeauducq avatar Nov 12 '18 04:11 sbourdeauducq

@sbourdeauducq Is it realistic to make only Signal and Constant hashable in the first place? AFAICT Migen does not rely on other values being hashable, but I might be wrong.

whitequark avatar Nov 12 '18 08:11 whitequark

Maybe, can you test it (including with ARTIQ)?

sbourdeauducq avatar Nov 12 '18 12:11 sbourdeauducq

OK

whitequark avatar Nov 12 '18 12:11 whitequark

I also just ran into this problem:

class OrderTest(Module):
    def __init__(self):
        counter = Signal(8)
        sig = Signal()
        self.sync += [
            counter.eq(counter + 1),
            If((counter == 1) or (counter == 2) or (counter == 3),
                sig.eq(1)
            )
        ]

print(str(verilog.convert(OrderTest())))

This results in:

...
      if ((counter == 2'd3)) begin
                sig <= 1'd1;
      end
...

xobs avatar Apr 18 '19 04:04 xobs

FYI this (and many other issues) are fixed in https://github.com/m-labs/nmigen/. But nMigen is not yet quite ready.

whitequark avatar Apr 18 '19 04:04 whitequark

Triage: fixed in nMigen.

whitequark avatar Jul 05 '19 14:07 whitequark

@sbourdeauducq @whitequark What is the correct way of doing logical AND or logical OR in Migen then? and_(a, b)? I couldn't find any example with something similar to _Operator("and", [a, b]) or _Operator("||", [a, b]) in the repository.

DurandA avatar Oct 29 '19 14:10 DurandA

(x == 2) & (y > 9)

jordens avatar Oct 29 '19 14:10 jordens

(x == 2) & (y > 9)

This is the bitwise operator, which does not behave like the logical operator.

DurandA avatar Oct 29 '19 14:10 DurandA

It does. For one bit expressions they are the same.

jordens avatar Oct 29 '19 16:10 jordens

In nMigen you can use x.bool() & y.bool() to get an equivalent of the logical AND that works regardless of the width of x and y.

whitequark avatar Oct 30 '19 02:10 whitequark

Thanks for your answers! Is there a bool() equivalent in Migen or should we use something like reduce(or_, a)?

DurandA avatar Oct 30 '19 10:10 DurandA

a != 0

jordens avatar Oct 30 '19 10:10 jordens