def visit_Attribute(s, node): if isinstance(node.value.Type, rt.Signal): dtype = node.value.Type.get_dtype() if not isinstance(dtype, rdt.Struct): raise PyMTLTypeError( s.blk, node.ast, 'attribute base should be a struct signal!') if not dtype.has_property(node.attr): raise PyMTLTypeError( s.blk, node.ast, f'{dtype.get_name()} does not have field {node.attr}!') dtype = dtype.get_property(node.attr) if isinstance(node.value.Type, rt.Port): rtype = rt.Port(node.value.Type.get_direction(), dtype) elif isinstance(node.value.Type, rt.Wire): rtype = rt.Wire(dtype) elif isinstance(node.value.Type, rt.Const): obj = node.value.Type.get_object() if obj is None: rtype = rt.Const(dtype) else: try: rtype = rt.Const(dtype, getattr(obj, node.attr)) except AttributeError: rtype = rt.Const(dtype) else: raise PyMTLTypeError( s.blk, node.ast, f'unrecognized signal type {node.value.Type}!') node.Type = rtype else: super().visit_Attribute(node)
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 visit_StructInst(s, node): cls = node.struct dtype = rdt.get_rtlir_dtype(cls()) all_properties = dtype.get_all_properties() if len(all_properties) != len(node.values): raise PyMTLTypeError( s.blk, node.ast, f"BitStruct {cls.__name__} has {len(all_properties)} fields but only {len(node.values)} arguments are given!" ) all_types = zip(node.values, list(all_properties.items())) for idx, (value, (name, field)) in enumerate(all_types): s.visit(value) # Expect each argument to be a signal if not isinstance(value.Type, rt.Signal): raise PyMTLTypeError( s.blk, node.ast, f"argument #{idx} has type {value.Type} but not a signal!") v_dtype = value.Type.get_dtype() # Expect each argument to have data type which corresponds to the field if v_dtype != field: raise PyMTLTypeError( s.blk, node.ast, f"Expected argument#{idx} ( field {name} ) to have type {field}, but got {v_dtype}." ) node.Type = rt.Const(dtype)
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)
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)]
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_)
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)]
def visit_StructInst( s, node ): cls = node.struct try: type_instance = cls() except TypeError: raise PyMTLTypeError( s.blk, node.ast, """"\ __init__ of BitStruct {} should take 0 arguments! You can achieve this by adding default values to the arguments. """.format( cls.__name__ ) ) dtype = rdt.get_rtlir_dtype( cls() ) all_properties = dtype.get_all_properties() if len( all_properties ) != len( node.values ): raise PyMTLTypeError( s.blk, node.ast, "BitStruct {} has {} fields but only {} arguments are given!". \ format(cls.__name__, len(all_properties), len(node.values)) ) all_types = zip( node.values, all_properties ) for idx, ( value, ( name, field ) ) in enumerate( all_types ): s.visit( value ) # Expect each argument to be a signal if not isinstance( value.Type, rt.Signal ): raise PyMTLTypeError( s.blk, node.ast, "argument #{} has type {} but not a signal!". \ format( idx, value.Type ) ) v_dtype = value.Type.get_dtype() # Expect each argument to have data type which corresponds to the field if v_dtype != field: raise PyMTLTypeError( s.blk, node.ast, "Expected argument#{} ( field {} ) to have type {}, but got {}.". \ format( idx, name, field, v_dtype ) ) node.Type = rt.Const( dtype )
def visit_LoopVar(s, node): node.Type = rt.Const(rdt.Vector(32), None)
def __init__(s, obj, value): super().__init__(rt.Const(rdt.get_rtlir_dtype(obj))) s.value = value
def test_pymtl3_list_consts(): a = CaseBits32x5ConstOnly.DUT() a.elaborate() assert rt.is_rtlir_convertible(a.in_) assert rt.get_rtlir(a.in_) == rt.Array([5], rt.Const(rdt.Vector(32)))
def test_pymtl_Bits_global(do_test): a = CaseBits32ClosureGlobal.DUT() a.elaborate() a._rtlir_freevar_ref = \ { 'pymtl_Bits_global_freevar' : ( pymtl_Bits_global_freevar, rt.Const(rdt.Vector(32), pymtl_Bits_global_freevar) ) } 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() l_explicit, r_explicit = node.left._is_explicit, node.right._is_explicit 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!" ) 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): if (not l_explicit and r_explicit) or (l_explicit and not r_explicit): 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 operation has {explicit} bits but " f"the integer literal requires more bits ({implicit})!" ) s.enforcer.enter(s.blk, context, op) elif not l_explicit and not r_explicit: # Both sides are implicit 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: # Both sides are explicit 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})!" ) res_nbits = max(l_nbits, r_nbits) node._is_explicit = l_explicit or r_explicit elif isinstance(op, s.BinOp_left_nbits): res_nbits = l_nbits node._is_explicit = l_explicit else: raise Exception('RTLIRTypeCheck internal error: unrecognized op!') try: # Both sides are constant expressions l_val = node.left._value r_val = node.right._value node._value = s.eval_const_binop(l_val, node.op, r_val) node.Type = s.rtlir_getter.get_rtlir(node._value) assert isinstance(node.Type, rt.Const) 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 visit_LoopVar(s, node): node.Type = rt.Const(rdt.Vector(s.loopvar_nbits[node.name]), None) node._is_explicit = s.loopvar_is_explicit[node.name]