def _symbolic_bind_array(self, param_type: ConcreteType, arg_type: ConcreteType): """Binds any parametric symbols in the "array" param_type.""" assert isinstance(param_type, ArrayType) and isinstance( arg_type, ArrayType) self._symbolic_bind(param_type.get_element_type(), arg_type.get_element_type()) self._symbolic_bind_dims(param_type, arg_type)
def _type_to_ir(self, concrete_type: ConcreteType) -> type_mod.Type: """Converts a concrete type to its corresponding IR representation.""" assert isinstance(concrete_type, ConcreteType), concrete_type logging.vlog(4, 'Converting concrete type to IR: %s', concrete_type) if isinstance(concrete_type, ArrayType): element_type = self._type_to_ir(concrete_type.get_element_type()) element_count = concrete_type.size if not isinstance(element_count, int): raise ValueError( 'Expect array element count to be integer; got {!r}'.format( element_count)) result = self.package.get_array_type(element_count, element_type) logging.vlog( 4, 'Converted type to IR; concrete type: %s ir: %s element_count: %d', concrete_type, result, concrete_type.size) return result elif isinstance(concrete_type, BitsType) or isinstance( concrete_type, EnumType): return self.package.get_bits_type(concrete_type.get_total_bit_count()) else: if not isinstance(concrete_type, TupleType): raise ValueError( 'Expect type to be bits/enum, array, or tuple; got: ' f'{concrete_type} ({concrete_type!r})') members = tuple( self._type_to_ir(m) for m in concrete_type.get_unnamed_members()) return self.package.get_tuple_type(members)
def _cast_to_array(self, node: ast.Cast, output_type: ConcreteType) -> None: bits = self._use(node.expr) slices = [] element_bit_count = output_type.get_element_type().get_total_bit_count() # pytype: disable=attribute-error # MSb becomes lowest-indexed array element. for i in range(0, output_type.get_total_bit_count(), element_bit_count): slices.append(self.fb.add_bit_slice(bits, i, element_bit_count)) slices.reverse() element_type = self.package.get_bits_type(element_bit_count) self._def(node, self.fb.add_array, slices, element_type)
def sign_convert_value(concrete_type: ConcreteType, value: Value) -> Value: """Converts the values to matched the signedness of the concrete type. Converts bits-typed Values contained within the given Value to match the signedness of the ConcreteType. Examples: invocation: sign_convert_value(s8, u8:64) returns: s8:64 invocation: sign_convert_value(s3, u8:7) returns: s3:-1 invocation: sign_convert_value((s8, u8), (u8:42, u8:10)) returns: (s8:42, u8:10) This conversion functionality is required because the Values used in the DSLX may be signed while Values in IR interpretation and Verilog simulation are always unsigned. This function is idempotent. Args: concrete_type: ConcreteType to match. value: Input value. Returns: Sign-converted value. """ if isinstance(concrete_type, concrete_type_mod.TupleType): assert value.is_tuple() assert len(value.tuple_members) == concrete_type.get_tuple_length() return Value.make_tuple( tuple( sign_convert_value(t, a) for t, a in zip( concrete_type.get_unnamed_members(), value.tuple_members))) elif isinstance(concrete_type, concrete_type_mod.ArrayType): assert value.is_array() assert len(value.array_payload.elements) == concrete_type.size return Value.make_array( tuple( sign_convert_value(concrete_type.get_element_type(), v) for v in value.array_payload.elements)) elif concrete_type_mod.is_sbits(concrete_type): return Value.make_sbits(value.get_bit_count(), value.get_bits_value()) else: assert concrete_type_mod.is_ubits(concrete_type) return value
def generate_argument(arg_type: ConcreteType, rng: Random, prior: Sequence[Value]) -> Value: """Generates an argument value of the same type as the concrete type.""" if isinstance(arg_type, TupleType): return Value.make_tuple( tuple( generate_argument(t, rng, prior) for t in arg_type.get_unnamed_members())) elif isinstance(arg_type, ArrayType): return Value.make_array( tuple( generate_argument(arg_type.get_element_type(), rng, prior) for _ in range(arg_type.size))) else: assert isinstance(arg_type, BitsType) if not prior or rng.random() < 0.5: return _generate_unbiased_argument(arg_type, rng) to_mutate = rng.choice(prior) bit_count = arg_type.get_total_bit_count() if bit_count > to_mutate.get_bit_count(): to_mutate = to_mutate.bits_payload.concat( _generate_bit_value(bit_count - to_mutate.get_bit_count(), rng, signed=False).bits_payload) else: to_mutate = to_mutate.bits_payload.slice(0, bit_count, lsb_is_0=False) assert to_mutate.bit_count == bit_count value = to_mutate.value mutation_count = randrange_biased_towards_zero(bit_count, rng) for _ in range(mutation_count): # Pick a random bit and flip it. bitno = rng.randrange(bit_count) value ^= 1 << bitno signed = arg_type.get_signedness() constructor = Value.make_sbits if signed else Value.make_ubits return constructor(value=value, bit_count=bit_count)
def _value_compatible_with_type(type_: ConcreteType, value: Value) -> bool: """Returns whether value is compatible with type_ (recursively).""" assert isinstance(value, Value), value if isinstance(type_, TupleType) and value.is_tuple(): return all( _value_compatible_with_type(ct, m) for ct, m in zip(type_.get_unnamed_members(), value.tuple_members)) if isinstance(type_, ArrayType) and value.is_array(): et = type_.get_element_type() return all( _value_compatible_with_type(et, m) for m in value.array_payload.elements) if isinstance(type_, EnumType) and value.tag == Tag.ENUM: return type_.nominal_type == value.type_ if isinstance(type_, BitsType) and not type_.signed and value.tag == Tag.UBITS: return value.bits_payload.bit_count == type_.get_total_bit_count() if isinstance(type_, BitsType) and type_.signed and value.tag == Tag.SBITS: return value.bits_payload.bit_count == type_.get_total_bit_count() if value.tag == Tag.ENUM and isinstance(type_, BitsType): return (value.type_.get_signedness() == type_.get_signedness() and value.bits_payload.bit_count == type_.get_total_bit_count()) if value.tag == Tag.ARRAY and is_ubits(type_): flat_bit_count = value.array_payload.flatten().bits_payload.bit_count return flat_bit_count == type_.get_total_bit_count() if isinstance(type_, EnumType) and value.is_bits(): return (type_.get_signedness() == (value.tag == Tag.SBITS) and type_.get_total_bit_count() == value.get_bit_count()) raise NotImplementedError(type_, value)
def concrete_type_convert_value(type_: ConcreteType, value: Value, span: Span, enum_values: Optional[Tuple[Value, ...]], enum_signed: Optional[bool]) -> Value: """Converts 'value' into a value of this concrete type.""" logging.vlog(3, 'Converting value %s to type %s', value, type_) if value.tag == Tag.UBITS and isinstance(type_, ArrayType): bits_per_element = type_.get_element_type().get_total_bit_count() bits = value.bits_payload def bit_slice_value_at_index(i): return Value( Tag.UBITS, bits.slice(i * bits_per_element, (i + 1) * bits_per_element, lsb_is_0=False)) return Value.make_array( tuple(bit_slice_value_at_index(i) for i in range(type_.size))) if (isinstance(type_, EnumType) and value.tag in (Tag.UBITS, Tag.SBITS, Tag.ENUM) and value.get_bit_count() == type_.get_total_bit_count()): # Check that the bits we're converting from are present in the enum type # we're converting to. for enum_value in enum_values: if value.bits_payload == enum_value.bits_payload: break else: raise FailureError( span, 'Value is not valid for enum {}: {}'.format( type_.nominal_type.identifier, value)) return Value.make_enum(value.bits_payload, type_.nominal_type) if (value.tag == Tag.ENUM and isinstance(type_, BitsType) and type_.get_total_bit_count() == value.get_bit_count()): constructor = Value.make_sbits if type_.signed else Value.make_ubits # pytype: disable=attribute-error bit_count = type_.get_total_bit_count() return constructor(bit_count, value.bits_payload.value) def zero_ext() -> Value: assert isinstance(type_, BitsType) constructor = Value.make_sbits if type_.signed else Value.make_ubits bit_count = type_.get_total_bit_count() return constructor( bit_count, value.get_bits_value() & bit_helpers.to_mask(bit_count)) def sign_ext() -> Value: assert isinstance(type_, BitsType) constructor = Value.make_sbits if type_.signed else Value.make_ubits bit_count = type_.get_total_bit_count() logging.vlog(3, 'Sign extending %s to %s', value, bit_count) return constructor(bit_count, value.bits_payload.sign_ext(bit_count).value) if value.tag == Tag.UBITS: return zero_ext() if value.tag == Tag.SBITS: return sign_ext() if value.tag == Tag.ENUM: assert enum_signed is not None return sign_ext() if enum_signed else zero_ext() # If we're converting an array into bits, flatten the array payload. if value.tag == Tag.ARRAY and isinstance(type_, BitsType): return value.array_payload.flatten() if concrete_type_accepts_value(type_, value): # Vacuous conversion. return value raise FailureError( span, 'Interpreter failure: cannot convert value %s (of type %s) to type %s' % (value, concrete_type_from_value(value), type_))