def __ne__(self, other): assert self._dtype is other._dtype if areValues(self, other): return self._ne__val(other) else: return Operator.withRes(AllOps.NEQ, [self, other], BOOL)
def bitsArithOp(self, other, op): other = toHVal(other, self._dtype) assert isinstance(other._dtype, Bits), other._dtype if areValues(self, other): return bitsArithOp__val(self, other, op._evalFn) else: if self._dtype.signed is None: self = self._unsigned() resT = self._dtype if isinstance(other._dtype, Bits): t0 = self._dtype t1 = other._dtype if t0.bit_length() != t1.bit_length(): if not t1.strict_width: # resize to type of this other = other._auto_cast(t1) t1 = other._dtype pass elif not t0.strict_width: # resize self to type of result self = self._auto_cast(t0) t0 = self._dtype pass else: raise TypeError("%r %r %r" % (self, op, other)) if t1.signed != resT.signed: other = other._convSign(t0.signed) else: raise TypeError("%r %r %r" % (self, op, other)) o = Operator.withRes(op, [self, other], self._dtype) return o._auto_cast(resT)
def __mul__(self, other): Bits = self._dtype.__class__ other = toHVal(other) if not isinstance(other._dtype, Bits): raise TypeError(other) if areValues(self, other): return self._mul__val(other) else: myT = self._dtype if self._dtype.signed is None: self = self._unsigned() if isinstance(other._dtype, Bits): s = other._dtype.signed if s is None: other = other._unsigned() else: raise TypeError("%r %r %r" % (self, AllOps.MUL, other)) if other._dtype == INT: res_w = myT.bit_length() * 2 res_sign = self._dtype.signed else: res_w = myT.bit_length() + other._dtype.bit_length() res_sign = self._dtype.signed or other._dtype.signed subResT = Bits(res_w, signed=res_sign) o = Operator.withRes(AllOps.MUL, [self, other], subResT) resT = Bits(res_w, signed=myT.signed) return o._auto_cast(resT)
def _concat(self, other): """ Concatenate this with other to one wider value/signal """ w = self._dtype.bit_length() try: other._dtype.bit_length except AttributeError: raise TypeError("Can not concat Bits and", other._dtype) if areValues(self, other): return self._concat__val(other) else: w = self._dtype.bit_length() other_w = other._dtype.bit_length() resWidth = w + other_w Bits = self._dtype.__class__ resT = Bits(resWidth, signed=self._dtype.signed) # is instance of signal if isinstance(other, InterfaceBase): other = other._sig if isinstance(other._dtype, Bits): if other._dtype.signed is not None: other = other._vec() elif other._dtype == BOOL: other = other._auto_cast(BIT) else: raise TypeError(other._dtype) if self._dtype.signed is not None: self = self._vec() return Operator.withRes(AllOps.CONCAT, [self, other], resT)\ ._auto_cast(Bits(resWidth, signed=self._dtype.signed))
def _eq(self, other): assert self._dtype is other._dtype if areHValues(self, other): return self._eq__val(other) else: return Operator.withRes(AllOps.EQ, [self, other], BOOL)
def __floordiv__(self, other) -> "Bits3val": other = toHVal(other) if isinstance(self, Value) and isinstance(other, Value): return Bits3val.__floordiv__(self, other) else: return Operator.withRes(AllOps.MUL, [self, other], self._dtype.__copy__())
def _convSign(self, signed): """ Convert signum, no bit manipulation just data are represented differently :param signed: if True value will be signed, if False value will be unsigned, if None value will be vector without any sign specification """ if isinstance(self, HValue): return self._convSign__val(signed) else: if self._dtype.signed == signed: return self t = copy(self._dtype) t.signed = signed if t.signed is not None: t.force_vector = True if signed is None: cnv = AllOps.BitsAsVec elif signed: cnv = AllOps.BitsAsSigned else: cnv = AllOps.BitsAsUnsigned return Operator.withRes(cnv, [self], t)
def bitsBitOp(self, other, op, getVldFn, reduceCheckFn): """ :attention: If other is Bool signal, convert this to bool (not ideal, due VHDL event operator) """ other = toHVal(other) iamVal = isinstance(self, Value) otherIsVal = isinstance(other, Value) if iamVal and otherIsVal: other = other._auto_cast(self._dtype) return bitsBitOp__val(self, other, op, getVldFn) else: if other._dtype == BOOL: self = self._auto_cast(BOOL) return op._evalFn(self, other) elif self._dtype == other._dtype: pass else: raise TypeError("Can not apply operator %r (%r, %r)" % (op, self._dtype, other._dtype)) if otherIsVal: r = reduceCheckFn(self, other) if r is not None: return r elif iamVal: r = reduceCheckFn(other, self) if r is not None: return r return Operator.withRes(op, [self, other], self._dtype)
def cast_integer(self, sigOrVal, toType): isVal = isinstance(sigOrVal, Value) if toType == BOOL: if isVal: v = int(bool(sigOrVal.val)) return HBoolVal(v, BOOL, sigOrVal.vldMask, sigOrVal.updateTime) elif isinstance(toType, Bits): if isVal: _v = sigOrVal.val w = toType.bit_length() assert _v.bit_length() <= w,\ "%d can not fit into %d bits" % (_v, w) v = toType.fromPy(_v) v.updateTime = sigOrVal.updateTime v._dtype = toType if not sigOrVal.vldMask: v.vldMask = 0 return v else: return Operator.withRes(AllOps.IntToBits, [sigOrVal], toType) return default_auto_cast_fn(self, sigOrVal, toType)
def _ternary(self, ifTrue, ifFalse): ifTrue = toHVal(ifTrue) ifFalse = toHVal(ifFalse) if isinstance(self, Value): return self._ternary__val(ifTrue, ifFalse) else: return Operator.withRes(AllOps.TERNARY, [self, ifTrue, ifFalse], ifTrue._dtype)
def boolCmpOp(self, other, op, evalFn=None): other = toHVal(other) if evalFn is None: evalFn = op._evalFn if areValues(self, other): return boolCmpOp__val(self, other, op, evalFn) else: return Operator.withRes(op, [self, other._auto_cast(BOOL)], BOOL)
def intOp(self, other, op, resT, evalFn=None): if evalFn is None: evalFn = op._evalFn other = toHVal(other)._auto_cast(INT) if areValues(self, other): return intOp__val(self, other, resT, evalFn) else: return Operator.withRes(op, [self, other], resT)
def __floordiv__(self, other) -> "Bits3val": other = toHVal(other, suggestedType=self._dtype) if isinstance(self, HValue) and isinstance(other, HValue): return Bits3val.__floordiv__(self, other) else: if not isinstance(other._dtype, self._dtype.__class__): raise TypeError() return Operator.withRes(AllOps.DIV, [self, other], self._dtype.__copy__())
def __neg__(self): if isinstance(self, HValue): return Bits3val.__neg__(self) else: if not self._dtype.signed: self = self._signed() resT = self._dtype o = Operator.withRes(AllOps.MINUS_UNARY, [self], self._dtype) return o._auto_cast(resT)
def _ternary(self, a, b): if isinstance(self, HValue): if self: return a else: return b else: a = toHVal(a) b = toHVal(b) return Operator.withRes(AllOps.TERNARY, [self, a, b], a._dtype.__copy__())
def __invert__(self): if isinstance(self, Value): return self._invert__val() else: try: # double negation d = self.singleDriver() if isinstance(d, Operator) and d.operator == AllOps.NOT: return d.operands[0] except (MultipleDriversErr, NoDriverErr): pass return Operator.withRes(AllOps.NOT, [self], self._dtype)
def __invert__(self): if isinstance(self, HValue): return Bits3val.__invert__(self) else: try: # double negation d = self.singleDriver() if isinstance(d, Operator) and d.operator == AllOps.NOT: return d.operands[0] except SignalDriverErr: pass return Operator.withRes(AllOps.NOT, [self], self._dtype)
def __mul__(self, other): Bits = self._dtype.__class__ other = toHVal(other) if not isinstance(other._dtype, Bits): raise TypeError(other) self_is_val = isinstance(self, HValue) other_is_val = isinstance(other, HValue) if self_is_val and other_is_val: return Bits3val.__mul__(self, other) else: # reduce *1 and *0 if self_is_val and self._is_full_valid(): _s = int(self) if _s == 0: return self._dtype.from_py(0) elif _s: return other._auto_cast(self._dtype) if other_is_val and other._is_full_valid(): _o = int(other) if _o == 0: return self._dtype.from_py(0) elif _o == 1: return self myT = self._dtype if self._dtype.signed is None: self = self._unsigned() if isinstance(other._dtype, Bits): s = other._dtype.signed if s is None: other = other._unsigned() else: raise TypeError("%r %r %r" % (self, AllOps.MUL, other)) if other._dtype == INT: res_w = myT.bit_length() res_sign = self._dtype.signed subResT = resT = myT else: res_w = max(myT.bit_length(), other._dtype.bit_length()) res_sign = self._dtype.signed or other._dtype.signed subResT = Bits(res_w, signed=res_sign) resT = Bits(res_w, signed=myT.signed) o = Operator.withRes(AllOps.MUL, [self, other], subResT) return o._auto_cast(resT)
def bitsBitOp(self, other, op, getVldFn, reduceCheckFn): """ :attention: If other is Bool signal, convert this to bool (not ideal, due VHDL event operator) """ other = toHVal(other, self._dtype) iamVal = isinstance(self, HValue) otherIsVal = isinstance(other, HValue) if iamVal and otherIsVal: other = other._auto_cast(self._dtype) return bitsBitOp__val(self, other, op._evalFn, getVldFn) else: s_t = self._dtype o_t = other._dtype if not isinstance(o_t, s_t.__class__): raise TypeError(o_t) if s_t == o_t: pass elif o_t == BOOL and s_t != BOOL: self = self._auto_cast(BOOL) return op._evalFn(self, other) elif o_t != BOOL and s_t == BOOL: other = other._auto_cast(BOOL) return op._evalFn(self, other) elif s_t.bit_length() == 1 and o_t.bit_length() == 1\ and s_t.signed is o_t.signed \ and s_t.force_vector != o_t.force_vector: if s_t.force_vector: self = self[0] else: other = other[0] else: raise TypeError("Can not apply operator %r (%r, %r)" % (op, self._dtype, other._dtype)) if otherIsVal: r = reduceCheckFn(self, other) if r is not None: return r elif iamVal: r = reduceCheckFn(other, self) if r is not None: return r return Operator.withRes(op, [self, other], self._dtype)
def _ternary(self, a, b): if isinstance(self, HValue): if self: return a else: return b else: a = toHVal(a) b = toHVal(b) try: if a == b: return a except ValidityError: pass return Operator.withRes(AllOps.TERNARY, [self, a, b], a._dtype.__copy__())
def convertBits(self, sigOrVal, toType): """ Cast signed-unsigned, to int or bool """ if isinstance(sigOrVal, Value): return convertBits__val(self, sigOrVal, toType) elif isinstance(toType, HBool): if self.bit_length() == 1: v = 0 if sigOrVal._dtype.negated else 1 return sigOrVal._eq(self.getValueCls().fromPy(v, self)) elif isinstance(toType, Bits): if self.bit_length() == toType.bit_length(): return sigOrVal._convSign(toType.signed) elif toType == INT: return Operator.withRes(AllOps.BitsToInt, [sigOrVal], toType) return default_auto_cast_fn(self, sigOrVal, toType)
def __getitem__(self, key): iamVal = isinstance(self, HValue) key = toHVal(key) isSLICE = isinstance(key, Slice.getValueCls()) if isSLICE: raise NotImplementedError() elif isinstance(key, (HValue, RtlSignalBase)): pass else: raise NotImplementedError( f"Index operation not implemented for index {key}") if iamVal and isinstance(key, HValue): return self._getitem__val(key) return Operator.withRes(AllOps.INDEX, [self, key], self._dtype.element_t)
def __getitem__(self, key): iamVal = isinstance(self, Value) key = toHVal(key) isSLICE = isinstance(key, Slice.getValueCls()) if isSLICE: raise NotImplementedError() elif isinstance(key, RtlSignalBase): key = key._auto_cast(INT) elif isinstance(key, Value): pass else: raise NotImplementedError( "Index operation not implemented for index %r" % (key)) if iamVal and isinstance(key, Value): return self._getitem__val(key) return Operator.withRes(AllOps.INDEX, [self, key], self._dtype.elmType)
def boolLogOp(self, other, op, getVldFn, reduceCheckFn): other = toHVal(other) iamVal = isinstance(self, Value) otherIsVal = isinstance(other, Value) if iamVal and otherIsVal: return boolLogOp__val(self, other, op, getVldFn) else: if otherIsVal: r = reduceCheckFn(self, other) if r is not None: return r elif iamVal: r = reduceCheckFn(other, self) if r is not None: return r return Operator.withRes(op, [self, other._auto_cast(BOOL)], BOOL)
def bitsArithOp(self, other, op): other = toHVal(other) assert isinstance(other._dtype, (Integer, Bits)) if areValues(self, other): return bitsArithOp__val(self, other, op) else: resT = self._dtype if self._dtype.signed is None: self = self._unsigned() if isinstance(other._dtype, Bits): assert other._dtype.bit_length() == resT.bit_length( ), (op, other._dtype.bit_length(), resT.bit_length()) other = other._convSign(self._dtype.signed) elif isinstance(other._dtype, Integer): pass else: raise TypeError("%r %r %r" % (self, op, other)) o = Operator.withRes(op, [self, other], self._dtype) return o._auto_cast(resT)
def bitsCmp(self, other, op, evalFn=None): """ :attention: If other is Bool signal convert this to bool (not ideal, due VHDL event operator) """ other = toHVal(other) t = self._dtype ot = other._dtype iamVal = isinstance(self, Value) otherIsVal = isinstance(other, Value) if evalFn is None: evalFn = op._evalFn if iamVal and otherIsVal: if ot == BOOL: self = self._auto_cast(BOOL) elif t == ot: pass elif isinstance(ot, Integer): other = other._auto_cast(t) else: raise TypeError("Values of types (%r, %r) are not comparable" % ( self._dtype, other._dtype)) return bitsCmp__val(self, other, op, evalFn) else: if ot == BOOL: self = self._auto_cast(BOOL) elif t == ot: pass elif isinstance(ot, Integer): other = other._auto_cast(self._dtype) else: raise TypeError("Values of types (%r, %r) are not comparable" % ( self._dtype, other._dtype)) return Operator.withRes(op, [self, other], BOOL)
def __neg__(self): if isinstance(self, Value): return self._neg__val() else: return Operator.withRes(AllOps.UN_MINUS, [self], INT)
def _downto(self, other): other = toHVal(other)._auto_cast(INT) if areValues(self, other): return self._downto__val(other) else: return Operator.withRes(AllOps.DOWNTO, [self, other], SLICE)
def bitsCmp(self, other, op, selfReduceVal, evalFn=None): """ Apply a generic comparison binary operator :attention: If other is Bool signal convert this to bool (not ideal, due VHDL event operator) :ivar self: operand 0 :ivar other: operand 1 :ivar op: operator used :ivar selfReduceVal: the value which is a result if operands are all same signal (e.g. a==a = 1, b<b=0) :ivar evalFn: override of a python operator function (by default one from "op" is used) """ t = self._dtype other = toHVal(other, t) ot = other._dtype if not isinstance(ot, t.__class__): raise TypeError(ot) if evalFn is None: evalFn = op._evalFn iamVal = isinstance(self, HValue) otherIsVal = isinstance(other, HValue) type_compatible = False if ot == BOOL: self = self._auto_cast(BOOL) type_compatible = True elif t == ot: type_compatible = True # lock type widht/signed to other type with elif not ot.strict_width or not ot.strict_sign: type_compatible = True other = other._auto_cast(t) elif not t.strict_width or not t.strict_sign: type_compatible = True other = other._auto_cast(ot) if iamVal and otherIsVal: if type_compatible: return bitsCmp__val(self, other, evalFn) else: if type_compatible: # try to reduce useless cmp res = None if otherIsVal and other._is_full_valid(): res = bitsCmp_detect_useless_cmp(self, other, op) elif iamVal and self._is_full_valid(): res = bitsCmp_detect_useless_cmp(other, self, CMP_OP_REVERSE[op]) if res is None: pass elif isinstance(res, HValue): return res else: assert res == AllOps.EQ, res op = res if self is other: return selfReduceVal else: return Operator.withRes(op, [self, other], BOOL) elif t.signed != ot.signed: if t.signed is None: self = self._convSign(ot.signed) return bitsCmp(self, other, op, evalFn) elif ot.signed is None: other = other._convSign(t.signed) return bitsCmp(self, other, op, evalFn) raise TypeError( f"Values of types ({self._dtype}, {other._dtype}) are not comparable")
def bitsBitOp(self, other, op: OpDefinition, getVldFn, reduceCheckFn, selfReduceVal): """ Apply a generic bitwise binary operator :attention: If other is Bool signal, convert this to bool (not ideal, due VHDL event operator) :ivar self: operand 0 :ivar other: operand 1 :ivar op: operator used :ivar getVldFn: function to resolve invalid (X) states :ivar reduceCheckFn: function to reduce useless operators (partially evaluate the expression if possible) :ivar selfReduceVal: the value which is a result if operands are all same signal (e.g. a&a = a, b^b=0) """ other = toHVal(other, self._dtype) iamVal = isinstance(self, HValue) otherIsVal = isinstance(other, HValue) if iamVal and otherIsVal: other = other._auto_cast(self._dtype) return bitsBitOp__val(self, other, op._evalFn, getVldFn) else: s_t = self._dtype o_t = other._dtype if not isinstance(o_t, s_t.__class__): raise TypeError(o_t) if s_t == o_t: pass elif o_t == BOOL and s_t != BOOL: self = self._auto_cast(BOOL) return op._evalFn(self, other) elif o_t != BOOL and s_t == BOOL: other = other._auto_cast(BOOL) return op._evalFn(self, other) else: if s_t.signed is not o_t.signed and bool(s_t.signed) == bool( o_t.signed): # automatically cast unsigned to vector if s_t.signed == False and o_t.signed is None: self = self._vec() s_t = self._dtype elif s_t.signed is None and o_t.signed == False: other = other._vec() o_t = other._dtype else: raise ValueError("Invalid value for signed flag of type", s_t.signed, o_t.signed, s_t, o_t) if s_t == o_t: # due to previsous cast the type may become the same pass elif s_t.bit_length() == 1 and o_t.bit_length() == 1\ and s_t.signed is o_t.signed \ and s_t.force_vector != o_t.force_vector: # automatically cast to vector with a single item to a single bit if s_t.force_vector: self = self[0] else: other = other[0] else: raise TypeError("Can not apply operator %r (%r, %r)" % (op, self._dtype, other._dtype)) if otherIsVal: r = reduceCheckFn(self, other) if r is not None: return r elif iamVal: r = reduceCheckFn(other, self) if r is not None: return r elif self is other: return selfReduceVal return Operator.withRes(op, [self, other], self._dtype)