# 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()
[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")
to_expr(a[0])
e0 = pop_expr()
to_expr(a[1])
e1 = pop_expr()
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:
to_expr(ai)
eai = pop_expr()
self.range_l.add_range(eai)
else:
to_expr(a)
e = pop_expr()
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")
to_expr(a[0])
e0 = pop_expr()
to_expr(a[1])
e1 = pop_expr()
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:
to_expr(ai)
eai = pop_expr()
self.range_l.add_range(eai)
else:
to_expr(a)
e = pop_expr()
self.range_l.add_range(e)
def __contains__(self, lhs):
to_expr(lhs)
return expr(ExprInModel(pop_expr(), 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)