phanrahan/magma

Does m.when support chaining comparison operators?

Closed this issue · 2 comments

Can comparison operators be chained in m.when?

class Test(m.Circuit):
    io = m.IO(
            CLK=m.In(m.Clock),
            load=m.In(m.Bit),
            value=m.In(m.UInt[16]),
            A=m.In(m.UInt[32]),
            C=m.Out(m.Bit)
    )
    value = m.Register(m.UInt[16], has_enable=True)()(I=io.value, CE=io.load)
    a = m.Register(m.UInt[32], has_enable=True)()(I=io.A, CE=io.load)
        
    with m.when(1 < a < m.zext(value, 16)):  # <-- Like this
        io.C @= 1
    with m.otherwise():
        io.C @= 0
Traceback (most recent call last):
  File "/home/giambla2/ws/magma_examples/magma_examples/test.py", line 253, in <module>
    class Test(m.Circuit):
  File "/home/giambla2/ws/magma_examples/magma_examples/test.py", line 266, in Test
    with m.when(1 < a.O < m.zext(value, 16)):
  File "/home/giambla2/.local/lib/python3.9/site-packages/magma/digital.py", line 233, in __bool__
    raise ValueError(
ValueError: Converting non-constant magma bit to bool not supported

This doesn't work because of how Python implements it under the hood.

It will turn an expression into the form 1 < a and a < value, the problem is that in Python we can't override the and operator (it invokes bool on the arguments and then does a logical and). Instead we'd want __and__ to be called (which is what happens when you call &) which "stages" the computation and constructs the hardware graph.

So for this pattern you'll need to explicitly & the two expressions rather than use the Python convenience syntax.

Thanks for the explanation, @leonardt.