Source code for vsc.types

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# Created on Jul 23, 2019
#
# @author: ballance


from enum import IntEnum, Enum, EnumMeta

from vsc.impl.ctor import push_expr, pop_expr, in_constraint_scope, \
    is_foreach_arr, expr_l, in_srcinfo_mode
from vsc.impl.enum_info import EnumInfo
from vsc.impl.expr_mode import is_expr_mode
from vsc.model.bin_expr_type import BinExprType
from vsc.model.enum_field_model import EnumFieldModel
from vsc.model.expr_array_subscript_model import ExprArraySubscriptModel
from vsc.model.expr_array_sum_model import ExprArraySumModel
from vsc.model.expr_bin_model import ExprBinModel
from vsc.model.expr_fieldref_model import ExprFieldRefModel
from vsc.model.expr_in_model import ExprInModel
from vsc.model.expr_indexed_field_ref_model import ExprIndexedFieldRefModel
from vsc.model.expr_literal_model import ExprLiteralModel
from vsc.model.expr_partselect_model import ExprPartselectModel
from vsc.model.expr_range_model import ExprRangeModel
from vsc.model.expr_rangelist_model import ExprRangelistModel
from vsc.model.expr_unary_model import ExprUnaryModel
from vsc.model.field_array_model import FieldArrayModel
from vsc.model.field_composite_model import FieldCompositeModel
from vsc.model.field_const_array_model import FieldConstArrayModel
from vsc.model.field_scalar_model import FieldScalarModel
from vsc.model.unary_expr_type import UnaryExprType
from vsc.model.value_scalar import ValueScalar, ValueInt


from vsc.impl.expr_mode import get_expr_mode, expr_mode, is_expr_mode
from vsc.model.expr_array_product_model import ExprArrayProductModel
from vsc.visitors.model_pretty_printer import ModelPrettyPrinter
from vsc.visitors.expr2field_visitor import Expr2FieldVisitor
from vsc.visitors.expr2fieldtype_visitor import Expr2FieldTypeVisitor
from vsc.model.expr_indexed_dynref_model import ExprIndexedDynRefModel
from vsc.model.source_info import SourceInfo


[docs] def unsigned(v, w=-1): if w == -1: w = 32 return expr(ExprLiteralModel(v, False, w))
[docs] def signed(v, w=-1): if w == -1: w = 32 return expr(ExprLiteralModel(v, True, w))
[docs] class expr(object): def __init__(self, em): push_expr(em) self.em = em
[docs] def bin_expr(self, op, rhs): to_expr(rhs) rhs_e = pop_expr() lhs_e = pop_expr() e = ExprBinModel(lhs_e, op, rhs_e) if in_srcinfo_mode(): e.srcinfo = SourceInfo.mk(2) return expr(e)
def __eq__(self, rhs): return self.bin_expr(BinExprType.Eq, rhs) def __ne__(self, rhs): return self.bin_expr(BinExprType.Ne, rhs) def __le__(self, rhs): return self.bin_expr(BinExprType.Le, rhs) def __lt__(self, rhs): return self.bin_expr(BinExprType.Lt, rhs) def __ge__(self, rhs): return self.bin_expr(BinExprType.Ge, rhs) def __gt__(self, rhs): return self.bin_expr(BinExprType.Gt, rhs) def __add__(self, rhs): return self.bin_expr(BinExprType.Add, rhs) def __sub__(self, rhs): return self.bin_expr(BinExprType.Sub, rhs) def __truediv__(self, rhs): return self.bin_expr(BinExprType.Div, rhs) def __floordiv__(self, rhs): return self.bin_expr(BinExprType.Div, rhs) def __mul__(self, rhs): return self.bin_expr(BinExprType.Mul, rhs) def __mod__(self, rhs): return self.bin_expr(BinExprType.Mod, rhs) def __and__(self, rhs): return self.bin_expr(BinExprType.And, rhs) def __or__(self, rhs): return self.bin_expr(BinExprType.Or, rhs) def __xor__(self, rhs): return self.bin_expr(BinExprType.Xor, rhs) def __lshift__(self, rhs): return self.bin_expr(BinExprType.Sll, rhs) def __rshift__(self, rhs): return self.bin_expr(BinExprType.Srl, rhs) def __neg__(self): return self.bin_expr(BinExprType.Not, rhs) def __invert__(self): lhs = pop_expr() return expr(ExprUnaryModel(UnaryExprType.Not, lhs))
[docs] def inside(self, rhs): lhs_e = pop_expr() if isinstance(rhs, rangelist): return expr(ExprInModel(lhs_e, rhs.range_l)) elif isinstance(rhs, list_t): return expr(ExprInModel( lhs_e, ExprRangelistModel( [ExprFieldRefModel(rhs.get_model())]))) else: raise Exception("Unsupported 'inside' argument of type " + str(type(rhs)) + "expect vsc.rangelist or list_t")
[docs] def outside(self, rhs): self.not_inside(rhs)
[docs] def not_inside(self, rhs): lhs_e = pop_expr() if isinstance(rhs, rangelist): return expr(ExprUnaryModel( UnaryExprType.Not, ExprInModel(lhs_e, rhs.range_l))) elif isinstance(rhs, list_t): return expr(ExprUnaryModel( UnaryExprType.Not, ExprInModel(lhs_e, ExprRangelistModel( [ExprFieldRefModel(rhs.get_model())])))) else: raise Exception("Unsupported 'not_inside' argument of type " + str(type(rhs)))
def __getattr__(self, name): if not expr_mode(): return object.__getattribute__(self, name) else: ret = None em = object.__getattribute__(self, "em") fm_t = Expr2FieldTypeVisitor().fieldtype(em) # This pops 'this expr' off the stack, so we can # replace it with an extended expression pop_expr() if fm_t is not None: if name in fm_t.field_id_m.keys(): idx = fm_t.field_id_m[name] ret = expr(ExprIndexedFieldRefModel(em, [idx])) else: raise Exception("Field %s not in type %s" % (name, fm_t.name)) else: fm = Expr2FieldVisitor().field(em) if name in fm.field_id_m.keys(): idx = fm.field_id_m[name] ret = expr(ExprIndexedFieldRefModel(em, [idx])) else: raise Exception("Composite %s does not contain a field \"%s\"" % ( fm.name, name)) return ret def __getitem__(self, k): if is_expr_mode(): if isinstance(k, slice): # Part-select on a field expression print("k=" + str(k) + " start=" + str(k.start) + " stop=" + str(k.stop)) to_expr(k.start) upper = pop_expr() to_expr(k.stop) lower = pop_expr() base_e = pop_expr() return expr(ExprPartselectModel(base_e, upper, lower)) else: # single value to_expr(k) idx_e = pop_expr() base_e = pop_expr() return expr_subscript(ExprArraySubscriptModel( base_e, idx_e)) else: raise Exception("Calling __getitem__ on an expr on non-expression context")
[docs] class dynamic_constraint_proxy(object): def __init__(self, em): self.em = em def __call__(self): return expr(self.em)
[docs] class expr_subscript(expr): def __init__(self, em): super().__init__(em) def __getattr__(self, aname): em = object.__getattribute__(self, "em") # This pops 'this expr' off the stack, so we can # replace it with an extended expression pop_expr() ret = None if isinstance(em, ExprArraySubscriptModel): # TODO: Need to get the core type fm = None if isinstance(em.lhs, ExprIndexedFieldRefModel): fm = em.lhs.get_target() elif isinstance(em.lhs, ExprFieldRefModel): fm = em.lhs.fm else: raise Exception("Unsupported path-chaining expression " + str(em.lhs)) if aname in fm.type_t.field_id_m.keys(): idx = fm.type_t.field_id_m[aname] ret = expr(ExprIndexedFieldRefModel(em, [idx])) elif aname in fm.type_t.constraint_dynamic_m.keys(): idx = fm.type_t.constraint_dynamic_m[aname] ret = dynamic_constraint_proxy(ExprIndexedDynRefModel(em, idx)) else: raise Exception("Type %s does not contain a field \"%s\"" % ( fm.type_t.name, aname)) else: raise Exception("Expression getattribute access on non-subscript") return ret
[docs] class rng(object): def __init__(self, low, high): to_expr(low) self.low = pop_expr() to_expr(high) self.high = pop_expr()
def _safe_to_expr_model(value): """ Safely convert a value to an expression model. This function creates an expr object via to_expr() and extracts the expression model (.em) directly. It also attempts to pop from the global expression stack to maintain balance, but handles IndexError gracefully in case the stack is empty or corrupted (which can happen during constraint solving failures). Note: to_expr() either: - Creates a new expr object (which pushes to stack in __init__), OR - Returns an existing expr object that's already on the stack In both cases, we need to pop to maintain stack balance. Args: value: The value to convert to an expression model Returns: The expression model object """ expr_obj = to_expr(value) model = expr_obj.em # Try to maintain stack balance, but don't fail if stack is corrupted try: pop_expr() except IndexError: # Stack was empty or corrupted, but we have the expression model pass return model
[docs] class rangelist(object): def __init__(self, *args): if len(args) == 0: raise Exception("Empty rangelist specified") self.range_l = ExprRangelistModel() for i in range(-1,-(len(args)+1), -1): a = args[i] if isinstance(a, tuple): # This needs to be a two-element array if len(a) != 2: raise Exception("Range specified with " + str(len(a)) + " elements is invalid. Two elements required") # Use helper to safely get expression models e0 = _safe_to_expr_model(a[0]) e1 = _safe_to_expr_model(a[1]) self.range_l.add_range(ExprRangeModel(e0, e1)) elif isinstance(a, rng): self.range_l.add_range(ExprRangeModel(a.low, a.high)) elif isinstance(a, list): for ai in a: eai = _safe_to_expr_model(ai) self.range_l.add_range(eai) else: e = _safe_to_expr_model(a) self.range_l.add_range(e) # self.range_l.rl.reverse() # This needs to be convertioble to a
[docs] def clear(self): self.range_l.rl.clear()
[docs] def extend(self, ranges): for a in ranges: self.append(a)
[docs] def append(self, a): if isinstance(a, tuple): # This needs to be a two-element array if len(a) != 2: raise Exception("Range specified with " + str(len(a)) + " elements is invalid. Two elements required") # Use helper to safely get expression models e0 = _safe_to_expr_model(a[0]) e1 = _safe_to_expr_model(a[1]) self.range_l.add_range(ExprRangeModel(e0, e1)) elif isinstance(a, rng): self.range_l.add_range(ExprRangeModel(a.low, a.high)) elif isinstance(a, list): for ai in a: eai = _safe_to_expr_model(ai) self.range_l.add_range(eai) else: e = _safe_to_expr_model(a) self.range_l.add_range(e)
def __contains__(self, lhs): lhs_model = _safe_to_expr_model(lhs) return expr(ExprInModel(lhs_model, self.range_l)) def __invert__(self): print("rangelist.__invert__")
[docs] def to_expr(t): if isinstance(t, expr): # This expression is already on the stack # push_expr(t.em) return t elif type(t) == int or type(t) == ValueInt: return expr(ExprLiteralModel(int(t), True, 32)) elif type(t) == float: return expr(ExprLiteralModel(int(round(t)), True, 32)) elif isinstance(type(t), (EnumMeta,IntEnum)): return expr(EnumInfo.get(type(t)).e2e(t)) elif isinstance(t, type): raise Exception("Illegal attempt to convert a type (%s) to a value" % str(t)) elif hasattr(t, "to_expr"): return t.to_expr() elif callable(t): raise Exception("TODO: support lambda references") else: raise Exception("Element \"" + str(t) + "\" isn't recognized, and doesn't provide to_expr (type=%s)" % str(type(t)))
[docs] class field_info(object): """Model-specific information about the field""" def __init__(self, is_composite=False): # a non-negative id means that this field # can be referenced via an indirect indexed # expression. This is used for coverage of # composite fields and for lists self.id = -1 self.parent = None self.root_e = None self.is_composite = is_composite self.name = None self.is_rand = False self.model = None # Specifies whether an ExprIndexedFieldRef should be used self.indexed_ref = False
[docs] def set_is_rand(self, is_rand): self.is_rand = is_rand if self.model is not None: self.model.is_declared_rand = is_rand
[docs] class type_base(object): """Base type for all primitive-type fields that participate in constraints""" def __init__(self, width, is_signed, i=0): self.width = width self.is_signed = is_signed self._init_val = i self._int_field_info = field_info()
[docs] def get_model(self): if self._int_field_info.model is None: self.build_field_model("<anonymous>") return self._int_field_info.model
[docs] def build_field_model(self, name): self._int_field_info.name = name if self._int_field_info.model is None: self._int_field_info.model = FieldScalarModel( name, self.width, self.is_signed, self._int_field_info.is_rand) self.set_val(self._init_val) else: # Ensure the name matches superstructure self._int_field_info.model.name = name return self._int_field_info.model
[docs] def to_expr(self): if self._int_field_info.id != -1: # A non-negative id means that this field # should be referenced indirectly. Follow the # parent/child relationships up to construct an # index list back to this field id_l = [] fi = self._int_field_info while fi.parent is not None: id_l.insert(0, fi.id) fi = fi.parent return expr(ExprIndexedFieldRefModel(fi.root_e, id_l)) else: return expr(ExprFieldRefModel(self._int_field_info.model))
@property def rand_mode(self): return self._int_field_info.model.rand_mode @rand_mode.setter def rand_mode(self, v): self._int_field_info.model.rand_mode = bool(v) @property def val(self): return int(self.get_model().get_val()) @val.setter def val(self, v): if self.is_signed: # TODO: handle signed masking self.get_model().set_val(ValueScalar(int(v))) else: # Mask the user-specified value v = int(v) & ((1 << self.width)-1) self.get_model().set_val(ValueScalar(v))
[docs] def get_val(self): return self.get_model().get_val().toInt()
[docs] def set_val(self, val): if self.is_signed: # TODO: handle signed masking self.get_model().set_val(ValueScalar(int(val))) else: # Mask the user-specified value val = int(val) & ((1 << self.width)-1) self.get_model().set_val(ValueScalar(val))
[docs] def bin_expr(self, op, rhs): to_expr(rhs) rhs_e = pop_expr() # push_expr(ExprFieldRefModel(self._int_field_info.model)) # Push a reference to this field self.to_expr() lhs_e = pop_expr() e = ExprBinModel(lhs_e, op, rhs_e) if in_srcinfo_mode(): e.srcinfo = SourceInfo.mk(2) return expr(e)
def __eq__(self, rhs): return self.bin_expr(BinExprType.Eq, rhs) def __ne__(self, rhs): return self.bin_expr(BinExprType.Ne, rhs) def __le__(self, rhs): return self.bin_expr(BinExprType.Le, rhs) def __lt__(self, rhs): return self.bin_expr(BinExprType.Lt, rhs) def __ge__(self, rhs): return self.bin_expr(BinExprType.Ge, rhs) def __gt__(self, rhs): return self.bin_expr(BinExprType.Gt, rhs) def __add__(self, rhs): return self.bin_expr(BinExprType.Add, rhs) def __sub__(self, rhs): return self.bin_expr(BinExprType.Sub, rhs) def __truediv__(self, rhs): return self.bin_expr(BinExprType.Div, rhs) def __floordiv__(self, rhs): return self.bin_expr(BinExprType.Div, rhs) def __mul__(self, rhs): return self.bin_expr(BinExprType.Mul, rhs) def __mod__(self, rhs): return self.bin_expr(BinExprType.Mod, rhs) def __and__(self, rhs): return self.bin_expr(BinExprType.And, rhs) def __or__(self, rhs): return self.bin_expr(BinExprType.Or, rhs) def __xor__(self, rhs): return self.bin_expr(BinExprType.Xor, rhs) def __lshift__(self, rhs): return self.bin_expr(BinExprType.Sll, rhs) def __rshift__(self, rhs): return self.bin_expr(BinExprType.Srl, rhs) def __neg__(self): return self.bin_expr(BinExprType.Not, rhs) def __invert__(self): self.to_expr() lhs = pop_expr() return expr(ExprUnaryModel(UnaryExprType.Not, lhs))
[docs] def inside(self, rhs): self.to_expr() lhs_e = pop_expr() if isinstance(rhs, rangelist): return expr(ExprInModel(lhs_e, rhs.range_l)) elif isinstance(rhs, rng): rl = ExprRangelistModel() rl.add_range(ExprRangeModel(rhs.low, rhs.high)) return expr(ExprInModel(lhs_e, rl)) elif isinstance(rhs, list_t): return expr(ExprInModel( lhs_e, ExprRangelistModel( [ExprFieldRefModel(rhs.get_model())]))) else: raise Exception("Unsupported 'inside' argument of type " + str(type(rhs)))
[docs] def outside(self, rhs): self.not_inside(rhs)
[docs] def not_inside(self, rhs): self.to_expr() lhs_e = pop_expr() if isinstance(rhs, rangelist): return expr(ExprUnaryModel( UnaryExprType.Not, ExprInModel(lhs_e, rhs.range_l))) elif isinstance(rhs, list_t): return expr(ExprUnaryModel( UnaryExprType.Not, ExprInModel(lhs_e, ExprRangelistModel( [ExprFieldRefModel(rhs.get_model())])))) else: raise Exception("Unsupported 'not_inside' argument of type " + str(type(rhs)) + " expect rangelist or list_t")
def __getitem__(self, rng): if is_expr_mode(): if isinstance(rng, slice): # slice to_expr(rng.start) upper = pop_expr() to_expr(rng.stop) lower = pop_expr() return expr(ExprPartselectModel( ExprFieldRefModel(self._int_field_info.model), upper, lower)) else: # single value to_expr(rng) e = pop_expr() return expr(ExprPartselectModel( ExprFieldRefModel(self._int_field_info.model), e)) else: curr = int(self.get_model().get_val()) if isinstance(rng, slice): msk = ((1 << (rng.start-rng.stop+1))-1) << rng.stop curr = (curr & msk) >> rng.stop else: curr = (curr & (1 << rng)) >> rng return curr def __setitem__(self, rng, val): if not is_expr_mode(): curr = int(self.get_model().get_val()) if isinstance(rng, slice): msk = ((1 << (rng.start-rng.stop))-1) << rng.stop curr = (curr & msk) | (val << rng.stop & msk) else: curr = (curr & ~(val << rng)) | (val << rng) self.get_model().set_val(curr) else: raise Exception("Cannot assign to a part-select within a constraint")
[docs] def clone(self): return type_base(self.width, self.is_signed)
[docs] class type_bool(type_base): """Base class for boolean fields""" def __init__(self, i=False): super().__init__(1, False, 1 if i else 0)
[docs] def build_field_model(self, name): # If we have an IntEnum, then collect the values self._int_field_info.name = name self._int_field_info.model = EnumFieldModel( name, self.enum_i.enums, self._int_field_info.is_rand ) return self._int_field_info.model
[docs] def get_val(self): """Gets the field value""" return bool(self.get_model().get_val())
[docs] def set_val(self, val): """Sets the field value""" self.get_model().set_val(bool(val))
[docs] class type_enum(type_base): """Base class for enumerated-type fields""" def __init__(self, t, i=None): # TODO: determine size of enum self.enum_i = EnumInfo.get(t) width = 32 is_signed = True super().__init__(width, is_signed, i) # The value of an enum field is stored in two ways # The enum_id is the index into the enum type # The 'val' field is the actual enum value self.enum_id = 0 if i is not None: # TODO # self.enum_id = list(t).f pass
[docs] def build_field_model(self, name): # If we have an IntEnum, then collect the values self._int_field_info.name = name self._int_field_info.model = EnumFieldModel( name, self.enum_i.enums, self._int_field_info.is_rand ) return self._int_field_info.model
[docs] def get_val(self): """Returns the enum id""" val = int(self.get_model().get_val()) return self.enum_i.v2e(val)
[docs] def set_val(self, val): """Sets the enum id""" self.get_model().set_val(self.enum_i.e2v(val))
[docs] class enum_t(type_enum): """Creates a non-random enumerated-type attribute""" def __init__(self, t, i=None): super().__init__(t, i)
[docs] class rand_enum_t(enum_t): """Creates a random enumerated-type attribute""" def __init__(self, t, i=None): super().__init__(t, i) self._int_field_info.is_rand = True
[docs] class bit_t(type_base): """Creates an unsigned arbitrary-width attribute""" def __init__(self, w=1, i=0): super().__init__(w, False, i)
[docs] class bool_t(type_base): """Creates a boolean field""" def __init__(self, i=False): super().__init__(1, False, 1 if i else 0)
[docs] class uint8_t(bit_t): """Creates an unsigned 8-bit attribute""" def __init__(self, i=0): super().__init__(8, i)
[docs] class uint16_t(bit_t): """Creates an unsigned 16-bit attribute""" def __init__(self, i=0): super().__init__(16, i)
[docs] class uint32_t(bit_t): """Creates an unsigned 32-bit attribute""" def __init__(self, i=0): super().__init__(32, i)
[docs] class uint64_t(bit_t): """Creates an unsigned 64-bit attribute""" def __init__(self, i=0): super().__init__(64, i)
[docs] class rand_bit_t(bit_t): """Creates a random unsigned arbitrary-width attribute""" def __init__(self, w=1, i=0): super().__init__(w, i) self._int_field_info.is_rand = True
[docs] class rand_uint8_t(rand_bit_t): """Creates a random unsigned 8-bit attribute""" def __init__(self, i=0): super().__init__(8, i)
[docs] class rand_uint16_t(rand_bit_t): """Creates a random unsigned 16-bit attribute""" def __init__(self, i=0): super().__init__(16, i)
[docs] class rand_uint32_t(rand_bit_t): """Creates a random unsigned 32-bit attribute""" def __init__(self, i=0): super().__init__(32, i)
[docs] class rand_uint64_t(rand_bit_t): """Creates a random unsigned 64-bit attribute""" def __init__(self, i=0): super().__init__(64, i)
[docs] class int_t(type_base): """Creates a signed arbitrary-width attribute""" def __init__(self, w=32, i=0): super().__init__(w, True, i)
[docs] class int8_t(int_t): """Creates a signed 8-bit attribute""" def __init__(self, i=0): super().__init__(8, i)
[docs] class int16_t(int_t): """Creates a signed 16-bit attribute""" def __init__(self, i=0): super().__init__(16, i)
[docs] class int32_t(int_t): """Creates a signed 32-bit attribute""" def __init__(self, i=0): super().__init__(32, i)
[docs] class int64_t(int_t): """Creates a signed 64-bit attribute""" def __init__(self, i=0): super().__init__(64, i)
[docs] class rand_int_t(int_t): """Creates a random signed arbitrary-width attribute""" def __init__(self, w=32, i=0): super().__init__(w, i) self._int_field_info.is_rand = True
[docs] class rand_int8_t(rand_int_t): """Creates a random signed 8-bit attribute""" def __init__(self, i=0): super().__init__(8, i)
[docs] class rand_int16_t(rand_int_t): """Creates a random signed 16-bit attribute""" def __init__(self, i=0): super().__init__(16, i)
[docs] class rand_int32_t(rand_int_t): """Creates a random signed 32-bit attribute""" def __init__(self, i=0): super().__init__(32, i)
[docs] class rand_int64_t(rand_int_t): """Creates a random signed 64-bit attribute""" def __init__(self, i=0): super().__init__(64, i)
[docs] class list_t(object): def __init__(self, t, sz=0, is_rand=False, is_randsz=False, init=None): self.t = t self._int_field_info = field_info() self.is_scalar = isinstance(t, (type_base,type_enum)) if self.is_scalar: self.mask = (1 << self.t.width)-1 self.is_enum = isinstance(t, type_enum) self._int_field_info.is_rand = is_rand self.is_rand_sz = is_randsz self.init_sz = sz self.init = init if self.init is not None and self.init_sz > 0: raise Exception("Only one of 'init' and 'sz' may be specified") if not self.is_scalar: if not hasattr(t, "_int_field_info"): raise Exception("list_t type " + str(t) + " (type " + str(type(t)) + ") is not a VSC randobj type") # Fill out field index and parent relationships # to support indexed field access # TODO: look out for recursive relationships... with expr_mode(): self._id_fields(t, None) # Non-scalar arrays require a backing array self.backing_arr = [] def _id_fields(self, it, parent): """Apply an ID to all fields, so they can be referenced in foreach constraints """ it._int_field_info.parent = parent fid = 0 for fn in dir(it): if not fn.startswith("__") and fn not in ("sum","product","size"): fo = getattr(it, fn) if hasattr(fo, "_int_field_info"): fi = fo._int_field_info fi.id = fid fi.parent = it._int_field_info fid += 1 if fi.is_composite: self._id_fields(fo, fi)
[docs] def get_model(self): if self._int_field_info.model is None: enums = None if not self.is_enum else self.t.enum_i.enums type_t = self.t.get_model() # Save the user-visible (Python) name for later use if hasattr(self.t, "name"): type_t.name = self.t.tname else: type_t.name = "<primitive>" self._int_field_info.model = FieldArrayModel( "<unknown-array>", type_t, self.is_scalar, enums, self.t.width if self.is_scalar else -1, self.t.is_signed if self.is_scalar else -1, self._int_field_info.is_rand, self.is_rand_sz) if self.init_sz > 0: if self.is_enum: ei : EnumInfo = self.t.enum_i ev = ei.v2e_m[ei.enums[0]] for i in range(self.init_sz): self.append(ev) elif self.is_scalar: for i in range(self.init_sz): self.append(0) else: for i in range(self.init_sz): self.append(type(self.t)()) elif self.init is not None: self.extend(self.init) return self._int_field_info.model
[docs] def build_field_model(self, name): model = self.get_model() model.name = name self._int_field_info.name = name return model
@property def size(self): model = self.get_model() if get_expr_mode(): return expr(ExprFieldRefModel(model.size)) else: return int(model.size.get_val()) @property def sum(self): if self.is_scalar: if get_expr_mode(): return expr(ExprArraySumModel(self.get_model())) else: ret = 0 for f in self.get_model().field_l: ret += int(f.get_val()) return ret else: raise Exception("Composite arrays do not have a sum") @property def product(self): if self.is_scalar: if get_expr_mode(): return expr(ExprArrayProductModel(self.get_model())) else: ret = 0 if self.size == 0 else 1 for f in self.get_model().field_l: ret *= int(f.get_val()) return ret else: raise Exception("Composite arrays do not have a product") def __len__(self): if get_expr_mode(): raise Exception("len cannot be used in constraints") else: return self.size
[docs] def append(self, v): model = self.get_model() if self.is_enum: ei : EnumInfo = self.t.enum_i enum_m = EnumFieldModel( "xxx", ei.enums, self._int_field_info.is_rand) enum_m.set_val(ei.e2v(v)) model.append(enum_m) elif self.is_scalar: # Working with a scalar f = model.add_field() mask_v = int(v) & self.mask f.set_val(mask_v) else: if not issubclass(type(v), type(self.t)): raise Exception("Attempting to append illegal element to object array") self.backing_arr.append(v) model.append(v.get_model()) # Propagate randomization information v.get_model().is_declared_rand = self.get_model().is_declared_rand
[docs] def extend(self, v): for vi in v: self.append(vi)
[docs] def clear(self): self.get_model().clear()
def __contains__(self, lhs): if get_expr_mode(): to_expr(lhs) return expr(ExprInModel( pop_expr(), ExprRangelistModel( [ExprFieldRefModel(self.get_model())]))) else: model = self.get_model() if self.is_enum: ei : EnumInfo = self.t.enum_i val = ei.e2v(lhs) for f in model.field_l: if int(f.get_val()) == val: return True elif self.is_scalar: for f in model.field_l: if int(f.get_val()) == int(lhs): return True else: return lhs in self.backing_arr return False def __iter__(self): class list_scalar_it(object): def __init__(self, l): self.l = l self.model = l._int_field_info.model self.idx = 0 def __iter__(self): return self def __next__(self): if self.idx >= int(self.model.size.get_val()): raise StopIteration() else: # The model's view is always masked 2's complement v = int(self.model.field_l[self.idx].get_val()) if self.l.t.is_signed: if (v & (1 << (self.l.t.width-1))) != 0: v = -((~v & self.l.mask)+1) self.idx += 1 return int(v) class list_object_it(object): def __init__(self, l): self.l = l self.model = l._int_field_info.model self.idx = 0 def __next__(self): if self.idx >= int(self.model.size.get_val()): raise StopIteration() else: v = self.l.backing_arr[self.idx] self.idx += 1 return v if self.is_scalar: return list_scalar_it(self) else: return list_object_it(self) def __getitem__(self, k): model = self.get_model() if get_expr_mode(): # TODO: must determine whether we're within a foreach or just on our own to_expr(k) idx_e = pop_expr() return expr_subscript(ExprArraySubscriptModel( ExprFieldRefModel(self.get_model()), idx_e)) # if is_foreach_arr(self): # to_expr(k) # idx_e = pop_expr() # # return expr_subscript(ExprArraySubscriptModel( # ExprFieldRefModel(self.get_model()), # idx_e)) # else: # to_expr(k) # idx_e = pop_expr() # return expr_subscript(ExprArraySubscriptModel( # ExprFieldRefModel(self.get_model()), # idx_e)) else: if self.is_enum: ei : EnumInfo = self.t.enum_i return ei.v2e(model.field_l[k].get_val()) elif self.is_scalar: # The model's view is always masked 2's complement v = int(model.field_l[k].get_val()) if self.t.is_signed: if (v & (1 << (self.t.width-1))) != 0: v = -((~v & self.mask)+1) return ValueInt(v) else: return self.backing_arr[k] def __setitem__(self, k, v): if self.is_enum: ei : EnumInfo = self.t.enum_i val = ei.e2v(v) self.get_model().field_l[k].set_val(val) elif self.is_scalar: self.get_model().field_l[k].set_val( ValueScalar(int(v) & (1 << self.t.width)-1)) else: self.backing_arr[k] = v def __str__(self): model = self.get_model() ret = "[" if self.is_enum: ei : EnumInfo = self.t.enum_i for i in range(self.size): if i > 0: ret += ", " ret += str(ei.v2e(model.field_l[i].get_val())) elif self.is_scalar: for i in range(self.size): if i > 0: ret += ", " ret += model.field_l[i].get_val().toString() else: for i in range(self.size): if i > 0: ret += ", " ret += str(self.backing_arr[i]) ret += "]" return ret
[docs] def to_expr(self): return expr(ExprFieldRefModel(self.get_model()))
[docs] class rand_list_t(list_t): """List of random elements with a non-random size""" def __init__(self, t, sz=0): super().__init__(t, sz, is_rand=True)
[docs] class randsz_list_t(list_t): """List of random elements with a random size""" def __init__(self, t): super().__init__(t, is_rand=True, is_randsz=True)