示例#1
0
  def visit_Slice( s, node ):
    lower_val = None if not hasattr(node.lower, "_value") else node.lower._value
    upper_val = None if not hasattr(node.upper, "_value") else node.upper._value
    dtype = node.value.Type.get_dtype()

    if not isinstance( dtype, rdt.Vector ):
      raise PyMTLTypeError( s.blk, node.ast, f'cannot perform slicing on type {dtype}!')

    if not lower_val is None and not upper_val is None:
      signal_nbits = dtype.get_length()
      # upper bound must be strictly larger than the lower bound
      if ( lower_val >= upper_val ):
        raise PyMTLTypeError( s.blk, node.ast,
          'the upper bound of a slice must be larger than the lower bound!' )
      # upper & lower bound should be less than the bit width of the signal
      if not ( 0 <= lower_val < upper_val <= signal_nbits ):
        raise PyMTLTypeError( s.blk, node.ast,
          'upper/lower bound of slice out of width of signal!' )
      node.Type = rt.NetWire( rdt.Vector( int( upper_val - lower_val ) ) )

    else:
      # Try to special case the constant-stride part selection
      try:
        assert isinstance( node.upper, bir.BinOp )
        assert isinstance( node.upper.op, bir.Add )
        nbits = node.upper.right
        slice_size = nbits._value
        assert s.is_same( node.lower, node.upper.left )
        node.Type = rt.NetWire( rdt.Vector( slice_size ) )
        # Add new fields that might help translation
        node.size = slice_size
        node.base = node.lower
      except Exception:
        raise PyMTLTypeError( s.blk, node.ast, 'slice bounds must be constant!' )
    def _handle_index_extension(s, node, value, idx, dscp, inclusive=True):
        expected_nbits = value.Type.get_index_width()
        idx_nbits = idx.Type.get_dtype().get_length()
        is_idx_reinterpretable = not idx._is_explicit

        if not inclusive and hasattr(idx, '_value'):
            idx_nbits = s._get_nbits_from_value(idx._value - 1)

        if idx_nbits > expected_nbits:
            # Either bitwidth do not match or requires implicit truncation
            raise PyMTLTypeError(
                s.blk, node.ast,
                f'expects a {expected_nbits}-bit index but the given {dscp} has more ({idx_nbits}) bits!'
            )
        elif idx_nbits < expected_nbits:
            if is_idx_reinterpretable:
                # Implicit zero-extension
                s.enforcer.enter(s.blk, rt.NetWire(rdt.Vector(expected_nbits)),
                                 idx)
            else:
                # Bitwidth mismatch
                raise PyMTLTypeError(
                    s.blk, node.ast,
                    f'expects a {expected_nbits}-bit index but the given {dscp} has {idx_nbits} bits!'
                )
        else:
            if idx_nbits != idx.Type.get_dtype().get_length():
                # If we used a different bitwidth then enforce it
                s.enforcer.enter(s.blk, rt.NetWire(rdt.Vector(idx_nbits)), idx)
示例#3
0
def test_pymtl3_list_interface_views():
    a = CaseBits32MsgRdyIfcOnly.DUT()
    a.elaborate()
    assert rt.is_rtlir_convertible(a.in_)
    assert rt.get_rtlir( a.in_ ) == \
        rt.Array([5], rt.InterfaceView('Bits32MsgRdyIfc',
        {'msg':rt.Port('output', rdt.Vector(32)), 'rdy':rt.Port('input', rdt.Vector(1))}))
示例#4
0
 def __init__(s, index_base, index):
     base_rtype = index_base.get_rtype()
     dtype = base_rtype.get_dtype()
     if isinstance(base_rtype, rt.Port):
         rtype = rt.Port(base_rtype.get_direction(), rdt.Vector(1))
     elif isinstance(base_rtype, rt.Wire):
         rtype = rt.Wire(rdt.Vector(1))
     else:
         assert False, f"unrecognized signal type {base_rtype} for indexing"
     super().__init__(index_base, index, rtype)
示例#5
0
def test_pymtl_list_components():
    a = CaseBits32InOutx5CompOnly.DUT()
    a.elaborate()
    assert rt.is_rtlir_convertible(a.b)
    assert rt.get_rtlir( a.b ) == \
    rt.Array([5], rt.Component( a.b[0], {
            'clk':rt.Port('input', rdt.Vector(1)),
            'reset':rt.Port('input', rdt.Vector(1)),
            'in_':rt.Port('input', rdt.Vector(32)),
            'out':rt.Port('output', rdt.Vector(32)),
          }))
示例#6
0
 def __init__( s, slice_base, start, stop ):
   base_rtype = slice_base.get_rtype()
   dtype = base_rtype.get_dtype()
   if isinstance( base_rtype, rt.Port ):
     rtype = rt.Port( base_rtype.get_direction(), rdt.Vector( stop-start ) )
   elif isinstance( base_rtype, rt.Wire ):
     rtype = rt.Wire( rdt.Vector( stop-start ) )
   else:
     assert False, f"unrecognized signal type {base_rtype} for slicing"
   super().__init__( rtype )
   s.base = slice_base
   s.slice = ( start, stop )
    def visit_IfExp(s, node):
        # Can the type of condition be cast into bool?
        if not rdt.Bool()(node.cond.Type.get_dtype()):
            raise PyMTLTypeError(
                s.blk, node.ast,
                'the condition of "if-exp" cannot be converted to bool!')

        # body and orelse must have the same type
        # if node.body.Type != node.orelse.Type:
        if not node.body.Type.get_dtype()(node.orelse.Type.get_dtype()):
            raise PyMTLTypeError(
                s.blk, node.ast,
                'the body and orelse of "if-exp" must have the same type!')

        lhs_dtype, rhs_dtype = node.body.Type.get_dtype(
        ), node.orelse.Type.get_dtype()
        lhs_is_vector = isinstance(lhs_dtype, rdt.Vector)
        rhs_is_vector = isinstance(rhs_dtype, rdt.Vector)
        lhs_nbits, rhs_nbits = lhs_dtype.get_length(), rhs_dtype.get_length()

        # Unify body and orelse if both are rdt.Vector
        if lhs_is_vector and rhs_is_vector and lhs_nbits != rhs_nbits:
            is_lhs_inferred = not node.body._is_explicit
            is_rhs_inferred = not node.orelse._is_explicit

            # Both sides are explicit
            if not is_lhs_inferred and not is_rhs_inferred:
                raise PyMTLTypeError(
                    s.blk, node.ast,
                    f'the body and orelse of "if-exp" have different bitwidth {lhs_nbits} vs {rhs_nbits}!'
                )

            # Both sides are implicit
            elif is_lhs_inferred and is_rhs_inferred:
                if lhs_nbits >= rhs_nbits:
                    target_nbits = lhs_nbits
                    op = node.body
                else:
                    target_nbits = rhs_nbits
                    op = node.orelse
                context = rt.NetWire(rdt.Vector(target_nbits))
                s.enforcer.enter(s.blk, context, op)

            else:
                # One side is explicit and the other implicit
                if is_lhs_inferred:
                    exp_str, imp_str = "or-else", "body"
                    context, op, explicit, implicit = node.orelse.Type, node.body, rhs_nbits, lhs_nbits
                else:
                    exp_str, imp_str = "body", "or-else"
                    context, op, explicit, implicit = node.body.Type, node.orelse, lhs_nbits, rhs_nbits
                if explicit < implicit:
                    raise PyMTLTypeError(
                        s.blk, node.ast,
                        f"The {exp_str} side of if-exp has {explicit} bits but "
                        f"the {imp_str} side requires more bits ({implicit})!")
                s.enforcer.enter(s.blk, context, op)

        node.Type = node.body.Type
        node._is_explicit = node.body._is_explicit or node.orelse._is_explicit
示例#8
0
def test_L1_const_numbers():
    a = CaseConstBits32AttrComp.DUT()
    a.elaborate()
    a.apply(StructuralRTLIRGenL1Pass(gen_connections(a)))
    consts = a.get_metadata(StructuralRTLIRGenL1Pass.consts)
    assert consts == [('const', rt.Array([5],
                                         rt.Const(rdt.Vector(32))), a.const)]
def test_L1_const_numbers():
    a = CaseConstBits32AttrComp.DUT()
    a.elaborate()
    a.apply(StructuralRTLIRGenL1Pass(gen_connections(a)))
    ns = a._pass_structural_rtlir_gen
    assert ns.consts == [('const', rt.Array([5], rt.Const(rdt.Vector(32))),
                          a.const)]
示例#10
0
def test_pymtl_Bits_closure_construct(do_test):
    a = CaseBits32ClosureConstruct.DUT()
    a.elaborate()
    a._rtlir_freevar_ref = {
        'foo_at_upblk': (a.fvar_ref, rt.Const(rdt.Vector(32), a.fvar_ref))
    }
    do_test(a)
示例#11
0
def test_pymtl_list_components():
    class B(dsl.Component):
        def construct(s):
            s.in_ = dsl.InPort(Bits32)
            s.out = dsl.OutPort(Bits32)

    class A(dsl.Component):
        def construct(s):
            s.b = [B() for _ in range(5)]

    a = A()
    a.elaborate()
    assert rt.is_rtlir_convertible(a.b)
    assert rt.Array([5], rt.Component( a.b[0],
      {'in_':rt.Port('input', rdt.Vector(32)), 'out':rt.Port('output', rdt.Vector(32))})) == \
          rt.get_rtlir( a.b )
  def visit_Compare( s, node ):
    l_type = node.left.Type.get_dtype()
    r_type = node.right.Type.get_dtype()
    l_explicit, r_explicit = node.left._is_explicit, node.right._is_explicit
    l_nbits, r_nbits = l_type.get_length(), r_type.get_length()

    if l_explicit and r_explicit:
      if l_type != r_type:
        raise PyMTLTypeError( s.blk, node.ast,
          f"LHS and RHS of {node.op.__class__.__name__} have different types ({l_type} vs {r_type})!" )

    elif not l_explicit and not r_explicit:
      if l_nbits >= r_nbits:
        target_nbits = l_nbits
        op = node.right
      else:
        target_nbits = r_nbits
        op = node.left
      context = rt.NetWire(rdt.Vector(target_nbits))
      s.enforcer.enter( s.blk, context, op )

    else:
      context, op, explicit, implicit = node.left.Type, node.right, l_nbits, r_nbits
      if not l_explicit:
        context, op, explicit, implicit = node.right.Type, node.left, r_nbits, l_nbits
      # Check if any implicit truncation happens
      if explicit < implicit:
        raise PyMTLTypeError( s.blk, node.ast,
            f"The explicitly sized side of comparison has {explicit} bits but "
            f"the integer literal requires more bits ({implicit}) to hold!" )
      s.enforcer.enter( s.blk, context, op )

    node.Type = rt.NetWire( rdt.Bool() )
    node._is_explicit = True
    def visit_Index(s, node):
        idx = None if not hasattr(node.idx, "_value") else node.idx._value
        if isinstance(node.value.Type, rt.Array):
            if idx is not None and not (0 <= idx <
                                        node.value.Type.get_dim_sizes()[0]):
                raise PyMTLTypeError(s.blk, node.ast,
                                     'array index out of range!')
            node.Type = node.value.Type.get_next_dim_type()
            obj = node.value.Type.get_obj()
            if idx is not None and obj is not None:
                if isinstance(node.Type, rt.Array):
                    node.Type.obj = obj[int(idx)]
                else:
                    node._value = obj[int(idx)]

        elif isinstance(node.value.Type, rt.Signal):
            dtype = node.value.Type.get_dtype()
            if node.value.Type.is_packed_indexable():
                if idx is not None and not (0 <= idx < dtype.get_length()):
                    raise PyMTLTypeError(s.blk, node.ast,
                                         'bit selection index out of range!')
                node.Type = node.value.Type.get_next_dim_type()
            elif isinstance(dtype, rdt.Vector):
                if idx is not None and not (0 <= idx < dtype.get_length()):
                    raise PyMTLTypeError(s.blk, node.ast,
                                         'bit selection index out of range!')
                node.Type = rt.NetWire(rdt.Vector(1))
            else:
                raise PyMTLTypeError(s.blk, node.ast,
                                     f'cannot perform index on {dtype}!')

        else:
            # Should be unreachable
            raise PyMTLTypeError(
                s.blk, node.ast, f'cannot perform index on {node.value.Type}!')
 def visit_Concat(s, node):
     nbits = 0
     for child in node.values:
         if not isinstance(child.Type, rt.Signal):
             raise PyMTLTypeError(s.blk, node.ast,
                                  f'{child} is not a signal!')
         nbits += child.Type.get_dtype().get_length()
     node.Type = rt.NetWire(rdt.Vector(nbits))
示例#15
0
def test_pymtl3_list_interface_views():
    class Ifc(dsl.Interface):
        def construct(s):
            s.msg = dsl.OutPort(Bits32)
            s.rdy = dsl.InPort(Bits1)

    class A(dsl.Component):
        def construct(s):
            s.in_ = [Ifc() for _ in range(5)]

    a = A()
    a.elaborate()
    assert rt.is_rtlir_convertible(a.in_)
    assert rt.Array([5],
      rt.InterfaceView('Ifc',
        {'msg':rt.Port('output', rdt.Vector(32)), 'rdy':rt.Port('input', rdt.Vector(1))})) == \
          rt.get_rtlir( a.in_ )
示例#16
0
def test_pymtl_signal():
    class A(Component):
        def construct(s):
            s.in_ = InPort(Bits32)

    a = A()
    a.elaborate()
    assert rdt.Vector(32) == rdt.get_rtlir_dtype(a.in_)
示例#17
0
def test_pymtl3_list_consts():
    class A(dsl.Component):
        def construct(s):
            s.in_ = [Bits32(42) for _ in range(5)]

    a = A()
    a.elaborate()
    assert rt.is_rtlir_convertible(a.in_)
    assert rt.Array([5], rt.Const(rdt.Vector(32))) == rt.get_rtlir(a.in_)
示例#18
0
def test_pymtl_struct_closure(do_test):
    a = CaseStructClosureGlobal.DUT()
    a.elaborate()
    a._rtlir_freevar_ref = {
        'foo_at_upblk':
        (a._foo,
         rt.Port("input", rdt.Struct("Bits32Foo", {"foo": rdt.Vector(32)})))
    }
    do_test(a)
    def visit_BinOp(s, node):
        op = node.op
        l_type = node.left.Type.get_dtype()
        r_type = node.right.Type.get_dtype()
        if not (rdt.Vector(1)(l_type) and rdt.Vector(1)(r_type)):
            raise PyMTLTypeError(
                s.blk, node.ast,
                f"both sides of {op.__class__.__name__} should be of vector type!"
            )

        if not isinstance(op, s.BinOp_left_nbits) and l_type != r_type:
            raise PyMTLTypeError(
                s.blk, node.ast,
                f"LHS and RHS of {op.__class__.__name__} should have the same type ({l_type} vs {r_type})!"
            )

        l_nbits = l_type.get_length()
        r_nbits = r_type.get_length()

        # Enforcing Verilog bitwidth inference rules
        res_nbits = 0
        if isinstance(op, s.BinOp_max_nbits):
            res_nbits = max(l_nbits, r_nbits)
        elif isinstance(op, s.BinOp_left_nbits):
            res_nbits = l_nbits
        else:
            raise Exception('RTLIRTypeCheck internal error: unrecognized op!')

        try:
            # Both sides are constant expressions
            l_val = node.left._value
            r_val = node.rigth._value
            node._value = s.eval_const_binop(l_val, op, r_val)
            node.Type = rt.Const(rdt.Vector(res_nbits))
        except AttributeError:
            # Both sides are constant but the value cannot be determined statically
            if isinstance(node.left.Type, rt.Const) and isinstance(
                    node.right.Type, rt.Const):
                node.Type = rt.Const(rdt.Vector(res_nbits), None)

            # Variable
            else:
                node.Type = rt.NetWire(rdt.Vector(res_nbits))
def test_L1_const_numbers():
    class A(dsl.Component):
        def construct(s):
            s.const = [Bits32(42) for _ in range(5)]

    a = A()
    a.elaborate()
    a.apply(StructuralRTLIRGenL1Pass(*gen_connections(a)))
    ns = a._pass_structural_rtlir_gen
    assert ns.consts == [('const', rt.Array([5], rt.Const(rdt.Vector(32))),
                          a.const)]
示例#21
0
def test_pymtl_list_multi_dimension():
    class A(dsl.Component):
        def construct(s):
            s.out = [[[dsl.OutPort(Bits32) for _ in range(1)] \
                    for _ in range(2)] for _ in range(3)]

    a = A()
    a.elaborate()
    assert rt.is_rtlir_convertible(a.out)
    assert rt.Array([3, 2, 1], rt.Port('output',
                                       rdt.Vector(32))) == rt.get_rtlir(a.out)
 def visit_Truncate(s, node):
     new_nbits = node.nbits
     child_type = node.value.Type
     old_nbits = child_type.get_dtype().get_length()
     if new_nbits > old_nbits:
         raise PyMTLTypeError(
             s.blk, node.ast,
             f'the target bitwidth {new_nbits} is larger than the bitwidth of the operand ({old_nbits})!'
         )
     node.Type = copy.copy(child_type)
     node.Type.dtype = rdt.Vector(new_nbits)
     node._is_explicit = True
def test_tmp_wire( do_test ):
  class A( dsl.Component ):
    def construct( s ):
      s.in_ = dsl.InPort( Bits32 )
      s.out = dsl.OutPort( Bits32 )
      @s.update
      def upblk():
        u = s.in_ + Bits32(42)
        s.out = u
  a = A()
  a.elaborate()
  a._rtlir_tmpvar_ref = {('u', 'upblk') : rt.Wire(rdt.Vector(32))}
  do_test( a )
示例#24
0
 def visit_SignExt( s, node ):
   try:
     new_nbits = node.nbits._value
   except AttributeError:
     raise PyMTLTypeError( s.blk, node.ast,
       f'{node.nbits} is not a constant number!' )
   child_type = node.value.Type
   old_nbits = child_type.get_dtype().get_length()
   if new_nbits <= old_nbits:
     raise PyMTLTypeError( s.blk, node.ast,
       f'{new_nbits} is not greater than {old_nbits}!' )
   node.Type = copy.copy( child_type )
   node.Type.dtype = rdt.Vector( new_nbits )
示例#25
0
def test_py_struct():
    @bitstruct
    class B:
        foo: Bits32

    class A(Component):
        def construct(s):
            s.in_ = InPort(B)

    a = A()
    a.elaborate()
    assert rdt.Struct('B',
                      {'foo': rdt.Vector(32)}) == rdt.get_rtlir_dtype(a.in_)
示例#26
0
def test_pymtl_packed_array():
    @bitstruct
    class B:
        foo: [Bits32] * 5

    class A(Component):
        def construct(s):
            s.in_ = InPort(B)

    a = A()
    a.elaborate()
    assert rdt.Struct( 'B', {'foo':rdt.PackedArray([5], rdt.Vector(32))} ) == \
           rdt.get_rtlir_dtype( a.in_ )
示例#27
0
def test_pymtl_packed_array():
    class B(BitStruct):
        def __init__(s, foo=42):
            s.foo = [Bits32(foo) for _ in range(5)]

    class A(Component):
        def construct(s):
            s.in_ = InPort(B)

    a = A()
    a.elaborate()
    assert rdt.Struct( 'B', {'foo':rdt.PackedArray([5], rdt.Vector(32))}, ['foo'] ) == \
           rdt.get_rtlir_dtype( a.in_ )
示例#28
0
def test_py_struct():
    class B(BitStruct):
        def __init__(s, foo=42):
            s.foo = Bits32(foo)

    class A(Component):
        def construct(s):
            s.in_ = InPort(B)

    a = A()
    a.elaborate()
    assert rdt.Struct('B', {'foo': rdt.Vector(32)},
                      ['foo']) == rdt.get_rtlir_dtype(a.in_)
    def visit_SizeCast(s, node):
        nbits = node.nbits
        Type = node.value.Type

        # We do not check for bitwidth mismatch here because the user should
        # be able to explicitly convert signals/constatns to different bitwidth.
        node.Type = copy.copy(Type)
        node.Type.dtype = rdt.Vector(nbits)

        try:
            node._value = node.value._value
        except AttributeError:
            pass
示例#30
0
    def visit_Slice(s, node):
        lower_val = getattr(node.lower, '_value', None)
        upper_val = getattr(node.upper, '_value', None)
        dtype = node.value.Type.get_dtype()

        if not isinstance(dtype, rdt.Vector):
            raise PyMTLTypeError(
                s.blk, node.ast,
                'cannot perform slicing on type {}!'.format(dtype))

        if not lower_val is None and not upper_val is None:
            signal_nbits = dtype.get_length()
            # upper bound must be strictly larger than the lower bound
            if (lower_val >= upper_val):
                raise PyMTLTypeError(
                    s.blk, node.ast,
                    'the upper bound of a slice must be larger than the lower bound!'
                )
            # upper & lower bound should be less than the bit width of the signal
            if not (0 <= lower_val < upper_val <= signal_nbits):
                raise PyMTLTypeError(
                    s.blk, node.ast,
                    'upper/lower bound of slice out of width of signal!')
            node.Type = rt.NetWire(rdt.Vector(int(upper_val - lower_val)))

        else:
            # Try to special case the constant-stride part selection
            try:
                assert isinstance(node.upper, bir.BinOp)
                assert isinstance(node.upper.op, bir.Add)
                nbits = node.upper.right
                assert s.is_same(node.lower, node.upper.left)
                node.Type = rt.NetWire(rdt.Vector(nbits))
            except Exception:
                raise PyMTLTypeError(s.blk, node.ast,
                                     'slice bounds must be constant!')