Source code for hwt.hdl.types.bitsRtlSignal

from copy import copy
from operator import eq
from typing import Union, Optional, Self, Literal

from hwt.constants import NOT_SPECIFIED
from hwt.doc_markers import internal
from hwt.hdl.const import HConst
from hwt.hdl.operator import HOperatorNode
from hwt.hdl.operatorDefs import HwtOps
from hwt.hdl.types.bitConstFunctions import bitsCmp, \
    bitsBitOp, bitsArithOp, bitsFloordiv, bitsMul, bitsLshift, \
    bitsRshift, HBitsAnyIndexCompatibleValue, HBitsAnyCompatibleValue, bitsRem, \
    bitsIsOn, HBits_common_operand_type_checks_for_self
from hwt.hdl.types.bitConstFunctionsGetitem import _get_operator_i_am_the_result_of, \
    bitsGetitem, _fold_concat_of_msb_using_sext
from hwt.hdl.types.bitConst_opReduce import tryReduceOr, tryReduceAnd, \
    tryReduceXor, reduceSigCheckFnAnd, reduceSigCheckFnOr, reduceSigCheckFnXor
from hwt.hdl.types.bits import HBits
from hwt.hdl.types.defs import BIT
from hwt.hdl.types.typeCast import toHVal
from hwt.mainBases import HwIOBase
from hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr
from hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal
from pyMathBitPrecise.bit_utils import ValidityError
from pyMathBitPrecise.bits3t import _NOT_SPECIFIED, Bits3val
from pyMathBitPrecise.bits3t_vld_masks import vld_mask_for_xor, vld_mask_for_and, \
    vld_mask_for_or


_SIGN_CAST_OPS = (HwtOps.BitsAsSigned, HwtOps.BitsAsUnsigned, HwtOps.BitsAsVec)


[docs] class HBitsRtlSignal(RtlSignal):
[docs] @internal def _cast_sign(self, signed: Optional[bool]) -> Self: """ 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 self._dtype.signed == signed: return self # try reduce useless cast like ux._signed()._unsigned() -> ux try: d = self.singleDriver() except SignalDriverErr: d = None if d is not None and isinstance(d, HOperatorNode): if d.operator in _SIGN_CAST_OPS and d.operands[0]._dtype.signed is signed: return d.operands[0] t = copy(self._dtype) t.signed = signed if t.signed is not None and t.bit_length() == 1: t.force_vector = True if signed is None: cnv = HwtOps.BitsAsVec elif signed: cnv = HwtOps.BitsAsSigned else: cnv = HwtOps.BitsAsUnsigned return HOperatorNode.withRes(cnv, [self], t)
[docs] def _signed(self) -> Self: return self._cast_sign(True)
[docs] def _unsigned(self) -> Self: return self._cast_sign(False)
[docs] def _vec(self) -> Self: return self._cast_sign(None)
[docs] def _concat(self, other: Union["HBitsConst", Self]) -> Self: """ Concatenate this with other to one wider value/signal """ try: other._dtype.bit_length except AttributeError: raise TypeError("Can not concat HBits with an object of unknown size or endianity", other) try: w = self._dtype.bit_length() other_w = other._dtype.bit_length() if isinstance(self, HwIOBase): self = self._sig if isinstance(other, HwIOBase): other = other._sig if isinstance(self, HBitsRtlSignal) and isinstance(other, HBitsRtlSignal): if w == 1: sext = _fold_concat_of_msb_using_sext(self, 1, other, other_w) if sext is not None: return sext else: # it may be sext of msb bit operator0 = _get_operator_i_am_the_result_of(self) if operator0 == HwtOps.SEXT: op0 = self.singleDriver() op0Src = op0.operands[0] if op0Src._dtype.bit_length() == 1: sext = _fold_concat_of_msb_using_sext(op0Src, int(op0.operands[1]), other, other_w) if sext is not None: # fold concat(x.msb.sext(), x) -> x.sext() return sext self = self._vec() resWidth = w + other_w HBits = self._dtype.__class__ resT = HBits(resWidth, signed=self._dtype.signed, force_vector=resWidth == 1) # is instance of signal if isinstance(other._dtype, HBits): if other._dtype.signed is not None: other = other._vec() else: raise TypeError(other._dtype) if self._dtype.signed is not None: self = self._vec() return HOperatorNode.withRes(HwtOps.CONCAT, [self, other], resT)\ ._auto_cast(HBits(resWidth, signed=self._dtype.signed)) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
[docs] def _ext(self, newWidth: Union[int, "HBitsConst"], signed: Union[bool, Literal[NOT_SPECIFIED]]=NOT_SPECIFIED) -> Self: """ construct zext/sext operator :note: preserves sign of type """ assert newWidth > 0, newWidth if signed is NOT_SPECIFIED: signed = bool(self._dtype.signed) else: assert isinstance(signed, bool), signed try: w = self._dtype.bit_length() extBitCnt = int(newWidth) - w except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified if extBitCnt < 0: raise AssertionError("newWidth >= current width", newWidth, w, self,) elif extBitCnt == 0: return self extOp = HwtOps.SEXT if signed else HwtOps.ZEXT try: resTy = self._dtype._createMutated(bit_length=w + extBitCnt) while True: # fold ext((ext(x))) -> ext(x) selfOp = _get_operator_i_am_the_result_of(self) if selfOp == extOp: self = self.singleDriver().operands[0] continue elif selfOp == HwtOps.CONCAT: d: HOperatorNode = self.singleDriver() assert len(d.operands) == 2 hiBits, loBits = d.operands newHiBitsExtWidth = newWidth - w + hiBits._dtype.bit_length() if isinstance(hiBits, HConst): hiBits = hiBits._ext(newHiBitsExtWidth, signed) # fold ext(concat(c, x)) to concat(cExtended, x) return hiBits._concat(loBits) else: selfHiBitsOp = _get_operator_i_am_the_result_of(hiBits) if selfHiBitsOp == extOp: # fold ext(concat(ext(x), y)) to concat(ext(x), y) return hiBits.singleDriver().operands[0]._ext(newHiBitsExtWidth, signed)._concat(loBits) break return HOperatorNode.withRes(extOp, [self, toHVal(newWidth)], resTy) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
[docs] def _sext(self, newWidth: Union[int, "HBitsConst"]) -> Self: """ signed extension, pad with MSB bit on MSB side to newWidth result width :see: :meth:`HBitsRtlSignal._ext` """ return self._ext(newWidth, True)
[docs] def _zext(self, newWidth: Union[int, "HBitsConst"]) -> Self: """ zero extension, pad with 0 on msb side to newWidth result width :see: :meth:`HBitsRtlSignal._ext` """ return self._ext(newWidth, False)
[docs] def _trunc(self, newWidth: Union[int, "HBitsConst"]): assert newWidth > 0, newWidth try: w = self._dtype.bit_length() cutBitCnt = w - int(newWidth) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified if cutBitCnt < 0: raise AssertionError("newWidth <= current width", newWidth, w, self,) elif cutBitCnt == 0: return self try: if newWidth == 1 and self._dtype.signed is None: # fold x._trunc(1) to x[0] return self[0] resTy = self._dtype._createMutated(bit_length=w - cutBitCnt) while True: # fold trunc((trunc(x))) -> trunc(x) # fold trunc(concat(a, x)) -> trunc(x) if trunc select only lower first (lsb) member of concat selfOp = _get_operator_i_am_the_result_of(self) if selfOp == HwtOps.TRUNC: self = self.singleDriver().operands[0] continue elif selfOp == HwtOps.BitsAsSigned or selfOp == HwtOps.BitsAsUnsigned: # fold x._signed()._trunc() to x._trunc()._signed() return selfOp._evalFn(self.singleDriver().operands[0]._trunc(newWidth)) elif selfOp == HwtOps.CONCAT: concLowBits = self.singleDriver().operands[0] concLowBitsWidth = concLowBits._dtype.bit_length() if concLowBitsWidth == resTy.bit_length(): return concLowBits elif concLowBitsWidth > resTy.bit_length(): self = concLowBits continue break return HOperatorNode.withRes(HwtOps.TRUNC, [self, toHVal(newWidth)], resTy) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
[docs] def _extOrTrunc(self, newWidth: int, signed: Union[bool, None, Literal[_NOT_SPECIFIED]]=_NOT_SPECIFIED) -> Self: return Bits3val._extOrTrunc(self, newWidth, signed)
def __getitem__(self, key: HBitsAnyIndexCompatibleValue) -> Union["HBitsConst", Self]: """ :see: :func:`bitsGetitem` """ try: return bitsGetitem(self, False, key) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __setitem__(self, index, value): raise TypeError("To assign a member of hdl array/vector/list/... use a[index](c) instead of a[index] = c") def __invert__(self) -> Self: HBits_common_operand_type_checks_for_self(self) try: # try reduce double negation d = self.singleDriver() if isinstance(d, HOperatorNode) and d.operator == HwtOps.NOT: return d.operands[0] except SignalDriverErr: pass return HOperatorNode.withRes(HwtOps.NOT, [self], self._dtype) def __hash__(self) -> int: return hash(id(self)) # comparisons
[docs] def _isOn(self) -> Self: try: return bitsIsOn(self) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
[docs] def _eq(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsCmp(self, False, other, HwtOps.EQ, BIT.from_py(1), eq) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
def __ne__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsCmp(self, False, other, HwtOps.NE, BIT.from_py(0)) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __lt__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsCmp(self, False, other, HwtOps.SLT if self._dtype.signed else HwtOps.ULT, BIT.from_py(0), evalFn=HwtOps.LT._evalFn) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __gt__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsCmp(self, False, other, HwtOps.SGT if self._dtype.signed else HwtOps.UGT, BIT.from_py(0), evalFn=HwtOps.GT._evalFn) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __ge__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsCmp(self, False, other, HwtOps.SGE if self._dtype.signed else HwtOps.UGE, BIT.from_py(1), evalFn=HwtOps.GE._evalFn) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __le__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsCmp(self, False, other, HwtOps.SLE if self._dtype.signed else HwtOps.ULE, BIT.from_py(1), evalFn=HwtOps.LE._evalFn) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified # bitwise def __xor__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsBitOp(self, False, other, HwtOps.XOR, vld_mask_for_xor, tryReduceXor, reduceSigCheckFnXor) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __and__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsBitOp(self, False, other, HwtOps.AND, vld_mask_for_and, tryReduceAnd, reduceSigCheckFnAnd) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __or__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsBitOp(self, False, other, HwtOps.OR, vld_mask_for_or, tryReduceOr, reduceSigCheckFnOr) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __lshift__(self, other: Union[int, "HBitsConst"]) -> Union[Self, "HBitsConst"]: try: return bitsLshift(self, other) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __rshift__(self, other: Union[int, "HBitsConst"]) -> Union[Self, "HBitsConst"]: try: return bitsRshift(self, other) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __neg__(self) -> Self: resT = self._dtype needsCast = not self._dtype.signed if needsCast: self = self._signed() o = HOperatorNode.withRes(HwtOps.MINUS_UNARY, [self], self._dtype) if needsCast: return o._reinterpret_cast(resT) else: return o # arithmetic def __sub__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsArithOp(self, False, other, HwtOps.SUB) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __add__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsArithOp(self, False, other, HwtOps.ADD) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __floordiv__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsFloordiv(self, False, other) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __mul__(self, other: HBitsAnyCompatibleValue) -> Union["HBitsConst", Self]: try: return bitsMul(self, False, other) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified def __mod__(self, other: HBitsAnyCompatibleValue) -> Union[Self, "HBitsConst"]: try: return bitsRem(self, True, other) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
[docs] def _ternary(self, vTrue: Union["HBitsConst", Self], vFalse: Union["HBitsConst", Self]) -> Union["HBitsConst", Self]: try: vTrue = toHVal(vTrue) vFalse = toHVal(vFalse, suggestedType=vTrue._dtype) try: if vTrue == vFalse: return vTrue except (ValidityError, NotImplementedError): pass if not (vTrue._dtype == vFalse._dtype): # all case values of ternary has to have same type vFalse = vFalse._auto_cast(vTrue._dtype) if vTrue._dtype.isScalar(): return HOperatorNode.withRes( HwtOps.TERNARY, [self, vTrue, vFalse], vTrue._dtype) else: # elementwise res = copy(vTrue) if isinstance(res, RtlSignal): raise NotImplementedError(vTrue) elif isinstance(res, HwIOBase): res._hwIOs = [] for iTrue in vTrue._hwIOs: iFalse = iTrue._onParentPropertyPath.getOnObject(vFalse) newI = self._ternary(iTrue, iFalse) iTrue._onParentPropertyPath.setOnObject(res, newI) res._hwIOs.append(newI) _fieldsToHwIOs = getattr(res, "_fieldsToHwIOs", None) else: for i, (t, f) in enumerate(zip(vTrue, vFalse)): res[i] = self._ternary(t, f) if _fieldsToHwIOs is not None: res._fieldsToHwIOs = {p: p.getOnObject(res) for p in _fieldsToHwIOs.keys()} return res except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
def __abs__(self): if not self._dtype.signed: return self return (self < 0)._ternary(-self, self)
[docs] def getMsb(self) -> Self: return self[self._dtype.bit_length() - 1]
[docs] def _onFallingEdge(self) -> Self: return HOperatorNode.withRes(HwtOps.FALLING_EDGE, [self], BIT)
[docs] def _onRisingEdge(self) -> Self: return HOperatorNode.withRes(HwtOps.RISING_EDGE, [self], BIT)
def __len__(self) -> int: return self._dtype.bit_length()