Exemplo n.º 1
0
def is_rtlir_convertible(obj):
    """Return if `obj` can be converted into an RTLIR instance."""
    pymtl_constructs = (
        dsl.InPort,
        dsl.OutPort,
        dsl.Wire,
        Bits,
        dsl.Interface,
        dsl.Component,
    )
    # TODO: improve this long list of isinstance check
    if isinstance(obj, list):
        while isinstance(obj, list):
            # Empty lists will be dropped
            if len(obj) == 0:
                return True
            obj = obj[0]
        return is_rtlir_convertible(obj)
    elif isinstance(obj, pymtl_constructs):
        return True
    elif is_bitstruct_inst(obj):
        return True
    elif isinstance(obj, int):
        return True
    else:
        return False
Exemplo n.º 2
0
def _get_rtlir_dtype_struct(obj):

    # Vector field
    if isinstance(obj, Bits):
        return Vector(obj.nbits)

    # PackedArray field
    elif isinstance(obj, list):
        assert len(obj) > 0, 'list length should be greater than 0!'
        ref_type = _get_rtlir_dtype_struct(obj[0])
        assert all( _get_rtlir_dtype_struct(i) == ref_type for i in obj ), \
          f'all elements of array {obj} must have the same type {ref_type}!'
        dim_sizes = []
        while isinstance(obj, list):
            assert len(obj) > 0, 'list length should be greater than 0!'
            dim_sizes.append(len(obj))
            obj = obj[0]
        return PackedArray(dim_sizes, _get_rtlir_dtype_struct(obj))

    # Struct field
    elif is_bitstruct_inst(obj):
        cls = obj.__class__

        properties = {
            name: _get_rtlir_dtype_struct(getattr(obj, name))
            for name in cls.__bitstruct_fields__.keys()
        }

        return Struct(cls.__name__, properties, cls)

    else:
        assert False, str(obj) + ' is not allowed as a field of struct!'
Exemplo n.º 3
0
    def _get_rtlir_cached(self, _obj):
        """Return an RTLIR instance corresponding to `obj`."""
        obj = _freeze(_obj)
        if obj in self._rtlir_cache:
            # self.cache_hit += 1
            # if self.cache_hit % 100 == 0:
            # print("hit", self.cache_hit, repr(_obj))
            return self._rtlir_cache[obj]
        else:
            # self.cache_miss += 1
            # if self.cache_miss % 100 == 0:
            # print("miss", self.cache_miss, repr(_obj))
            try:
                for Type, handler in self._RTLIR_handlers:
                    if isinstance(_obj, Type):
                        ret = self._rtlir_cache[obj] = handler(NA, _obj)
                        return ret
                if is_bitstruct_inst(_obj):
                    ret = self._rtlir_cache[obj] = self._handle_Const(NA, _obj)
                    return ret

                # Cannot convert `obj` into RTLIR representation
                assert False, f'unrecognized object {_obj}!'
            except AssertionError as e:
                msg = '' if e.args[0] is None else e.args[0]
                raise RTLIRConversionError(_obj, msg)
Exemplo n.º 4
0
def get_rtlir_dtype(obj):
    """Return the RTLIR data type of obj."""
    try:
        assert not isinstance(obj, list), \
          'array datatype object should be a field of some struct!'

        # Signals might be parameterized with different data types
        if isinstance(obj, (dsl.Signal, dsl.Const)):
            Type = obj._dsl.Type
            assert isinstance(Type, type)

            # Vector data type
            if issubclass(Type, Bits):
                return Vector(Type.nbits)

            # python int object
            elif Type is int:
                return Vector(32)

            # Struct data type
            elif is_bitstruct_class(Type):
                try:
                    return _get_rtlir_dtype_struct(Type())
                except TypeError:
                    assert False, \
                      f'__init__() of supposed struct {Type.__name__} should take 0 argument ( you can \
            achieve this by adding default values to your arguments )!'

            else:
                assert False, f'cannot convert object of type {Type} into RTLIR!'

        # Python integer objects
        elif isinstance(obj, int):
            # Following the Verilog bitwidth rule: number literals have 32 bit width
            # by default.
            return Vector(32)

        # PyMTL Bits objects
        elif isinstance(obj, Bits):
            return Vector(obj.nbits)

        # PyMTL BitStruct objects
        elif is_bitstruct_inst(obj):
            return _get_rtlir_dtype_struct(obj)

        else:
            assert False, 'cannot infer the data type of the given object!'
    except AssertionError as e:
        msg = '' if e.args[0] is None else e.args[0]
        raise RTLIRConversionError(obj, msg)
Exemplo n.º 5
0
 def _get_arg_str(name, obj):
     # Support common python types and Bits/BitStruct
     if isinstance(obj, (int, bool, str)):
         return str(obj)
     elif obj == None:
         return 'None'
     elif isinstance(obj, Bits):
         nbits = obj.nbits
         value = int(obj)
         Bits_name = f"Bits{nbits}"
         Bits_arg_str = f"{Bits_name}( {value} )"
         if Bits_name not in symbols and nbits >= 256:
             Bits_class = mk_bits(nbits)
             symbols.update({Bits_name: Bits_class})
         return Bits_arg_str
     elif is_bitstruct_inst(obj):
         raise TypeError(
             "Do you really want to pass in an instance of "
             "a BitStruct? Contact PyMTL developers!")
         # This is hacky: we don't know how to construct an object that
         # is the same as `obj`, but we do have the object itself. If we
         # add `obj` to the namespace of `construct` everything works fine
         # but the user cannot tell what object is passed to the constructor
         # just from the code.
         # Do not use a double underscore prefix because that will be
         # interpreted differently by the Python interpreter
         # bs_name = ("_" if name[0] != "_" else "") + name + "_obj"
         # if bs_name not in symbols:
         # symbols.update( { bs_name : obj } )
         # return bs_name
     elif isinstance(obj, type) and issubclass(obj, Bits):
         nbits = obj.nbits
         Bits_name = f"Bits{nbits}"
         if Bits_name not in symbols and nbits >= 256:
             Bits_class = mk_bits(nbits)
             symbols.update({Bits_name: Bits_class})
         return Bits_name
     elif is_bitstruct_class(obj):
         BitStruct_name = obj.__name__
         if BitStruct_name not in symbols:
             symbols.update({BitStruct_name: obj})
         return BitStruct_name
     # FIXME formalize this
     elif isinstance(obj, type) and hasattr(
             obj, 'req') and hasattr(obj, 'resp'):
         symbols.update({obj.__name__: obj})
         return obj.__name__
     raise TypeError(
         f"Interface constructor argument {obj} is not an int/Bits/BitStruct/TypeTuple!"
     )
Exemplo n.º 6
0
    def _connect_signal_const(s, o1, o2):
        Type = o1._dsl.Type
        if isinstance(o2, int):
            if not issubclass(Type, (int, Bits)):
                raise InvalidConnectionError(
                    f"We don't support connecting an integer constant "
                    f"to non-int/Bits type {Type}")
            o2 = Const(Type, Type(o2), s)
        elif isinstance(o2, Bits):
            Type2 = type(o2)
            if not issubclass(Type, Bits):
                raise InvalidConnectionError(
                    f"We don't support connecting a {Type2} constant "
                    f"to non-Bits type {Type}")
            if Type is not Type2:
                raise InvalidConnectionError(
                    f"Bitwidth mismatch when connecting a {Type2} constant "
                    f"to signal {o1} with type {Type}.")
            o2 = Const(Type, o2, s)
        elif is_bitstruct_inst(o2):
            Type2 = type(o2)
            if Type is not Type2:
                raise InvalidConnectionError(
                    f"We don't support connecting a {Type2} constant bitstruct"
                    f"to non-bitstruct type {Type}")
            o2 = Const(Type, o2, s)
        else:
            raise InvalidConnectionError(
                f"\n>>> {o2} of type {type(o2)} is not a const! \n"
                f">>> It cannot be connected to signal {o1} of type {o1._dsl.Type}!\n"
                f"Suggestion: fix the RHS of connection to be an instance of {o1._dsl.Type}."
            )

        # TODO implement connecting a const struct

        host = o1.get_host_component()

        if isinstance(o1, InPort):
            # connecting constant to inport should be at the parent level
            host = host.get_parent_object()

        o2._dsl.parent_obj = s
        s._dsl.consts.add(o2)

        # o2 should be a new object

        s._dsl.adjacency[o1].add(o2)
        s._dsl.adjacency[o2].add(o1)

        s._dsl.connect_order.append((o1, o2))
Exemplo n.º 7
0
    def visit_Attribute(s, node):
        """Return the SystemVerilog representation of an attribute.

    Add support for accessing struct attribute in L3.
    """
        if isinstance(node.value.Type, rt.Signal):
            if isinstance(node.value.Type, rt.Const):
                try:
                    obj = node.Type.get_object()
                except AttributeError:
                    obj = None
                if obj is None:
                    raise SVerilogTranslationError(
                        s.blk, node,
                        f"attribute ({node.attr}) of constant struct instance ({node.value}) is not supported!"
                    )
                else:
                    if isinstance(obj, Bits):
                        s.signal_expr_prologue(node)
                        node.sexpr['s_attr'] = \
                            s._literal_number(obj.nbits, int(obj))
                        node.sexpr["s_index"] = ""
                        attr = node.attr
                        return s.signal_expr_epilogue(node, f"{attr}")
                    elif is_bitstruct_inst(obj):
                        s.signal_expr_prologue(node)
                        node.sexpr['s_attr'] = \
                            s._struct_instance(node.Type.get_dtype(), obj)
                        node.sexpr["s_index"] = ""
                        attr = node.attr
                        return s.signal_expr_epilogue(node, f"{attr}")
                    else:
                        raise SVerilogTranslationError(
                            s.blk, node,
                            f"attribute ({node.attr}) of constant struct instance ({node.value}) is not supported!"
                        )

            elif isinstance(node.value.Type.get_dtype(), rdt.Struct):
                value = s.visit(node.value)
                s.signal_expr_prologue(node)
                attr = node.attr
                s.check_res(node, attr)
                node.sexpr['s_attr'] += "__{}"
                node.sexpr['attr'].append(attr)
                return s.signal_expr_epilogue(node, f"{value}.{attr}")

        return super().visit_Attribute(node)
Exemplo n.º 8
0
  def enter( s, node ):
    ret = s.visit( node )
    # Constant objects that are recognized
    # 1. int, BitsN( X )
    # 2. BitsN
    # 3. BitStruct, BitStruct()
    # 4. Functions, including concat, zext, sext, etc.
    is_value = isinstance(ret, (int, Bits)) or is_bitstruct_inst(ret)
    is_type = isinstance(ret, type) and (issubclass(ret, Bits) or is_bitstruct_class(ret))
    try:
      is_function = ret in s.pymtl_functions
    except:
      is_function = False

    if is_value or is_type or is_function:
      return ret
    else:
      return None
Exemplo n.º 9
0
  def _get_rtlir_uncached( self, _obj ):
    # global uncached
    """Return an RTLIR instance corresponding to `obj`."""
    obj = _freeze( _obj )

    try:
      for Type, handler in self._RTLIR_handlers:
        if isinstance( _obj, Type ):
          # uncached +=1
          # if uncached % 100 == 0:
            # print('uncached', uncached, repr(_obj), handler)
          return handler( "<NA>", _obj )
      if is_bitstruct_inst( _obj ):
        return self._handle_Const( "<NA>", _obj )

      # Cannot convert `obj` into RTLIR representation
      assert False, f'unrecognized object {_obj}!'
    except AssertionError as e:
      msg = '' if e.args[0] is None else e.args[0]
      raise RTLIRConversionError( _obj, msg )
Exemplo n.º 10
0
    def visit_Attribute(s, node):

        s.signal_expr_prologue(node)

        Type = node.Type

        if isinstance(Type, rt.Const):
            obj = Type.get_object()
            if isinstance(obj, int):
                nbits = node.Type.get_dtype().get_length()
                node.sexpr['s_attr'] = f"{nbits}'d{obj}"
                node.sexpr['s_index'] = ""
            elif isinstance(obj, Bits):
                # nbits = obj.nbits
                nbits = node.Type.get_dtype().get_length()
                value = int(obj)
                node.sexpr['s_attr'] = f"{nbits}'d{value}"
                node.sexpr['s_index'] = ""
            elif is_bitstruct_inst(obj):
                node.sexpr['s_attr'] = s._struct_instance(
                    node.Type.get_dtype(), obj)
                node.sexpr['s_index'] = ""
            else:
                raise VerilogTranslationError(
                    s.blk, node, f"{node.attr} {obj} is not an integer!")

        elif isinstance(node.value, bir.Base):
            # The base of this attribute node is the component 's'.
            # Example: s.out, s.STATE_IDLE
            # assert node.value.base is s.component
            s.check_res(node, node.attr)
            node.sexpr['s_attr'] = "{}"
            node.sexpr['attr'].append(node.attr)

        else:
            raise VerilogTranslationError(
                s.blk, node, "sub-components are not supported at L1")

        return s.signal_expr_epilogue(node, node.attr)
Exemplo n.º 11
0
def get_rtlir(_obj):
    """Return an RTLIR instance corresponding to `obj`."""
    obj = _freeze(_obj)
    if obj in _rtlir_cache:
        return _rtlir_cache[obj]
    else:
        try:
            for Type, handler in _RTLIR_handlers:
                if isinstance(_obj, Type):
                    ret = _rtlir_cache[obj] = handler("<name not available>",
                                                      _obj)
                    return ret
            if is_bitstruct_inst(_obj):
                ret = _rtlir_cache[obj] = _handle_Const(
                    "<name not available>", _obj)
                return ret

            # Cannot convert `obj` into RTLIR representation
            assert False, f'unrecognized object {_obj}!'
        except AssertionError as e:
            msg = '' if e.args[0] is None else e.args[0]
            raise RTLIRConversionError(_obj, msg)
Exemplo n.º 12
0
def gen_signal_expr(cur_component, signal):
    """Return an RTLIR signal expression for the given signal."""

    try:
        if isinstance(signal, dsl.Const):
            c = signal._dsl.const
            assert isinstance( c, ( int, Bits )) or is_bitstruct_inst( c ), \
                              f'{c} is not an integer/Bits/BitStruct const!'
            return ConstInstance(signal, c)

        assert isinstance(signal, dsl.Signal), f'{signal} is not supported!'

        # Strip off all the tokens from the signal to the component

        tmp = signal
        stack = []

        if tmp.is_sliced_signal():
            stack.append((construct_slice, tmp._dsl.slice))
            tmp = tmp.get_parent_object()

        while tmp is not cur_component:
            if tmp._dsl._my_indices:
                for x in reversed(tmp._dsl._my_indices):
                    stack.append((construct_index, x))
            stack.append((construct_attr, tmp._dsl._my_name))
            tmp = tmp.get_parent_object()

        cur_node = construct_base(tmp, tmp._dsl.my_name)

        for f, token in reversed(stack):
            cur_node = f(cur_node, token)

        return cur_node

    except AssertionError as e:
        msg = '' if e.args[0] is None else e.args[0]
        raise RTLIRConversionError(signal, msg)
Exemplo n.º 13
0
def gen_signal_expr( cur_component, signal ):
  """Return an RTLIR signal expression for the given signal."""

  def get_next_op( expr, cur_pos, my_name, full_name ):
    """Return the next signal operation in string `expr`.

    Return value: ( op, *data )
    op is one of [ 'Attr', 'Slice', 'Index', 'Base', 'Done' ].
    *data is one to two variables that describes the next signal operation.
    """
    if not expr[cur_pos:]: return ( 'Done', '' ), 0
    pos = len( expr )
    dot_pos = expr.find( '.', cur_pos+1 )
    lb_pos  = expr.find( '[', cur_pos+1 )
    pos = dot_pos if dot_pos != -1 and dot_pos < pos else pos
    pos =  lb_pos if  lb_pos != -1 and  lb_pos < pos else pos

    # Attribute operation
    if expr[cur_pos] == '.': return ( 'Attr', expr[cur_pos+1:pos] ), pos

    # Index or slice operation
    elif expr[cur_pos] == '[':
      rb_pos = expr.find( ']', cur_pos )
      colon_pos = expr.find( ':', cur_pos )
      assert rb_pos != -1 and pos == rb_pos+1, \
        f"unrecognized expression {expr}"

      if cur_pos < colon_pos < rb_pos:
        start = int( expr[cur_pos+1:colon_pos] )
        stop  = int( expr[colon_pos+1:rb_pos] )
        return ( 'Slice', start, stop ), pos
      else:
        return ( 'Index', int(expr[cur_pos+1:rb_pos]) ), pos

    # The current component ( base of attribute )
    else:
      base_pos = expr.find( full_name )
      assert base_pos >= 0, \
        f"cannot find the base of attribute {full_name} in {expr}"
      return ( 'Base', my_name ), base_pos + len( full_name )

  def get_cls_inst( func_list, cur_node, ops ):
    """Return an IR instance of the given signal operation."""
    classes = [ c for c in ( f( cur_node, *ops ) for f in func_list ) if c ]
    assert len(classes) <= 1, f"internal error: not unique class {classes}!"
    assert classes, f"internal error: no available expression nodes for {cur_node}!"
    return classes[0]( cur_node, *ops )

  try:

    try:
      expr = signal._dsl.full_name
      base_comp = signal
    except AttributeError:
      # Special case for a ConstInstance because it has no name
      assert hasattr( signal._dsl, 'const' ), f'{signal} is not supported!'
      c = signal._dsl.const
      assert isinstance( c, ( int, Bits )) or is_bitstruct_inst( c ), \
          f'{signal._dsl.const} is not an integer/Bits/BitStruct const!'
      return ConstInstance( signal, c )

    # Get the base component
    base_comp = cur_component
    full_name = base_comp._dsl.full_name
    my_name = base_comp._dsl.my_name
    assert expr.find( full_name ) >= 0, \
      f"cannot find the base of attribute {full_name} in {expr}"

    # Start from the base component and process one operation per iteration
    cur_pos, cur_node = 0, base_comp
    while cur_pos < len( expr ):
      op, next_pos = get_next_op( expr, cur_pos, my_name, full_name )
      if op[0] == 'Done': break
      cur_node = get_cls_inst( signal_expr_classes[ op[0] ], cur_node, op[1:] )
      cur_pos = next_pos
    return cur_node

  except AssertionError as e:
    msg = '' if e.args[0] is None else e.args[0]
    raise RTLIRConversionError( signal, msg )