def slice_to_SLICE(sliceVals, width): """convert python slice to value of SLICE hdl type""" if sliceVals.step is not None: raise NotImplementedError() start = sliceVals.start stop = sliceVals.stop if sliceVals.start is None: start = INT.fromPy(width) else: start = toHVal(sliceVals.start) if sliceVals.stop is None: stop = INT.fromPy(0) else: stop = toHVal(sliceVals.stop) startIsVal = isinstance(start, Value) stopIsVal = isinstance(stop, Value) indexesAreValues = startIsVal and stopIsVal if indexesAreValues: updateTime = max(start.updateTime, stop.updateTime) else: updateTime = -1 return Slice.getValueCls()((start, stop), SLICE, 1, updateTime)
def _connectToIter(self, master, exclude=None, fit=False): # [todo] implementatino for RtlSignals of HStruct type if exclude and (self in exclude or master in exclude): return if self._interfaces: for ifc in self._interfaces: if exclude and ifc in exclude: continue mIfc = getattr(master, ifc._name) if exclude and mIfc in exclude: continue if mIfc._masterDir == DIRECTION.OUT: if ifc._masterDir != mIfc._masterDir: raise IntfLvlConfErr("Invalid connection", ifc, "<=", mIfc) yield from ifc._connectTo(mIfc, exclude=exclude, fit=fit) else: if ifc._masterDir != mIfc._masterDir: raise IntfLvlConfErr("Invalid connection", mIfc, "<=", ifc) yield from mIfc._connectTo(ifc, exclude=exclude, fit=fit) else: dstSig = toHVal(self) srcSig = toHVal(master) if fit: srcSig = fitTo(srcSig, dstSig) yield dstSig(srcSig)
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 _connectToIter(self, master, exclude, fit): # [todo] implementation for RtlSignals of HStruct type if exclude and (self in exclude or master in exclude): return if self._interfaces: seen_master_intfs = [] for ifc in self._interfaces: if exclude and ifc in exclude: mIfc = getattr(master, ifc._name, None) if mIfc is not None: seen_master_intfs.append(mIfc) continue mIfc = getattr(master, ifc._name) seen_master_intfs.append(mIfc) if exclude and mIfc in exclude: continue if mIfc._masterDir == DIRECTION.OUT: if ifc._masterDir != mIfc._masterDir: raise IntfLvlConfErr("Invalid connection", ifc, "<=", mIfc) yield from ifc._connectToIter(mIfc, exclude, fit) else: if ifc._masterDir != mIfc._masterDir: raise IntfLvlConfErr("Invalid connection", mIfc, "<=", ifc) yield from mIfc._connectToIter(ifc, exclude, fit) if len(seen_master_intfs) != len(master._interfaces): if exclude: # there is a possiblity that the master interface was excluded, # but we did not see it as the interface of the same name was not present on self for ifc in self._interfaces: if ifc in exclude or ifc not in seen_master_intfs: continue else: # ifc is an interface which is extra on master and is missing an equivalent on slave raise InterfaceStructureErr(self, master, exclude) else: raise InterfaceStructureErr(self, master, exclude) else: if master._interfaces: raise InterfaceStructureErr(self, master, exclude) dstSig = toHVal(self) srcSig = toHVal(master) if fit: srcSig = fitTo(srcSig, dstSig) yield dstSig(srcSig)
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 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 hardcodeRomIntoProcess(cls, rom): """ Due to verilog restrictions it is not posible to use array constants and rom memories has to be hardcoded as process """ processes = [] signals = [] for e in rom.endpoints: assert isinstance(e, Operator) and e.operator == AllOps.INDEX, e me, index = e.operands assert me is rom # construct output of the rom romValSig = rom.ctx.sig(rom.name, dtype=e.result._dtype) romValSig.hidden = False signals.append(romValSig) # construct process which will represent content of the rom cases = [(toHVal(i), [romValSig(v), ]) for i, v in enumerate(rom.def_val.val)] romSwitchStm = SwitchContainer(index, cases) for (_, (stm,)) in cases: stm.parentStm = romSwitchStm p = HWProcess(rom.name, [romSwitchStm, ], {index, }, {index, }, {romValSig, }) processes.append(p) # override usage of original index operator on rom # to use signal generated from this process for _e in e.result.endpoints: _e._replace_input(e.result, romValSig) rom.hidden = True return processes, signals
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 __call__(self, source) -> Assignment: """ Create assignment to this signal :attention: it is not call of function it is operator of assignment :return: list of assignments """ if isinstance(source, InterfaceBase): assert source._isAccessible source = source._sig if source is None: source = self._dtype.from_py(None) else: source = toHVal(source, suggestedType=self._dtype) err = False try: source = source._auto_cast(self._dtype) except TypeConversionErr: err = True if err: raise TypeConversionErr( ("Can not connect %r (of type %r) to %r " "(of type %r) due type incompatibility") % (source, source._dtype, self, self._dtype)) tmp = self._getIndexCascade() if tmp: mainSig, indexCascade = tmp self = mainSig else: indexCascade = None # self = self._tryMyIndexToEndpoint() return Assignment(source, self, indexCascade)
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 _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 __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 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 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 evalParam(p): """ Get value of parameter """ while isinstance(p, Param): p = p.get() if isinstance(p, RtlSignalBase): return p.staticEval() # use rather param inheritance instead of param as param value return toHVal(p)
def __init__(self, initval): initval = toHVal(initval) super(Param, self).__init__(None, None, initval._dtype, defVal=initval) self._val = initval self.replacedWith = None self._parent = None self.__isReadOnly = False # {unit: (ctx, name)} self._scopes = {} self._const = True self.hidden = False
def SignalItem(cls, si, ctx, declaration=False): if declaration: ctx = ctx.forSignal(si) v = si.defVal if si.virtualOnly: pass elif si.drivers: pass elif si.endpoints or si.simSensProcs: if not v.vldMask: raise SerializerException( "Signal %s is constant and has undefined value" % si.name) else: raise SerializerException( "Signal %s should be declared but it is not used" % si.name) t = si._dtype dimensions = [] while isinstance(t, HArray): # collect array dimensions dimensions.append(t.size) t = t.elmType s = "%s%s %s" % (getIndent(ctx.indent), cls.HdlType(t, ctx), si.name) if dimensions: # to make a space between name and dimensoins dimensions = list( map(lambda x: "[%s-1:0]" % cls.asHdl(toHVal(x), ctx), dimensions)) dimensions.append("") s += " ".join(reversed(dimensions)) if isinstance(v, RtlSignalBase): if v._const: return s + " = %s" % cls.asHdl(v, ctx) else: # default value has to be set by reset because it is only signal return s elif isinstance(v, Value): if v.vldMask: return s + " = %s" % cls.Value(v, ctx) else: return s else: raise NotImplementedError(v) else: return cls.get_signal_name(si, ctx)
def __call__( self, source, dst_resolve_fn=lambda x: x._getDestinationSignalForAssignmentToThis() ) -> Assignment: """ Create assignment to this signal :attention: it is not call of function it is operator of assignment :return: list of assignments """ assert not self._const, self if isinstance(source, InterfaceBase): assert source._isAccessible, ( source, "must be a Signal Interface which is accessible in current scope" ) source = source._sig try: requires_type_check = False if source is None: source = self._dtype.from_py(None) else: requires_type_check = True source = toHVal(source, suggestedType=self._dtype) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified if requires_type_check: err = False try: source = source._auto_cast(self._dtype) except TypeConversionErr: err = True if err: raise TypeConversionErr( ("Can not connect %r (of type %r) to %r " "(of type %r) due type incompatibility") % (source, source._dtype, self, self._dtype)) try: mainSig, indexCascade = self._getIndexCascade() mainSig = dst_resolve_fn(mainSig) return Assignment(source, mainSig, indexCascade) except Exception as e: # simplification of previous exception traceback e_simplified = copy(e) raise e_simplified
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 hardcodeRomIntoProcess(cls, rom): """ Due to verilog restrictions it is not posible to use array constants and rom memories has to be hardcoded as process """ processes = [] signals = [] for e in rom.endpoints: assert isinstance(e, Operator) and e.operator == AllOps.INDEX, e me, index = e.operands assert me is rom # construct output of the rom romValSig = rom.ctx.sig(rom.name, dtype=e.result._dtype) signals.append(romValSig) romValSig.hidden = False # construct process which will represent content of the rom cases = [(toHVal(i), [ romValSig(v), ]) for i, v in enumerate(rom.defVal.val)] statements = [ SwitchContainer(index, cases), ] for (_, (stm, )) in cases: stm.parentStm = statements[0] p = HWProcess(rom.name, statements, { index, }, { index, }, { romValSig, }) processes.append(p) # override usage of original index operator on rom # to use signal generated from this process def replaceOrigRomIndexExpr(x): if x is e.result: return romValSig else: return x for _e in e.result.endpoints: _e.operands = tuple(map(replaceOrigRomIndexExpr, _e.operands)) e.result = romValSig return processes, signals
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 In(sigOrVal, iterable): """ HDL convertible "in" operator, check if any of items in "iterable" equals "sigOrVal" """ res = None for i in iterable: i = toHVal(i) if res is None: res = sigOrVal._eq(i) else: res = res | sigOrVal._eq(i) assert res is not None, "argument iterable is empty" return res
def set(self, val): """ set value of this param """ assert not self.__isReadOnly, \ ("This parameter(%s) was locked" " and now it can not be changed" % self.name) assert self.replacedWith is None, \ ("This param was replaced with new one and this " "should not exists") val = toHVal(val) self.defVal = val self._val = val.staticEval() self._dtype = self._val._dtype
def Case(self, caseVal, *statements): "c-like case of switch statement" assert self.parentStm is None caseVal = toHVal(caseVal, self.switchOn._dtype) assert isinstance(caseVal, HValue), caseVal assert caseVal._is_full_valid(), "Cmp with invalid value" assert caseVal not in self._case_value_index, ( "Switch statement already has case for value ", caseVal) self.rank += 1 case = [] self._case_value_index[caseVal] = len(self.cases) self.cases.append((caseVal, case)) self._register_stements(statements, case) return self
def __call__(self, source): """ assign to signal which is next value of this register :return: list of assignments """ if isinstance(source, InterfaceBase): source = source._sig if source is None: source = self._dtype.from_py(None) else: source = toHVal(source) source = source._auto_cast(self._dtype) a = Assignment(source, self.next) return [a, ]
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 _connect(src, dst, exclude, fit): if isinstance(src, InterfaceBase): if isinstance(dst, InterfaceBase): return dst._connectTo(src, exclude=exclude, fit=fit) src = src._sig assert not exclude, "this intf. is just a signal" if src is None: src = dst._dtype.fromPy(None) else: src = toHVal(src) if fit: src = fitTo(src, dst) src = src._auto_cast(dst._dtype) return dst(src)
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 _connect(src, dst, exclude, fit): # [TODO]: support for RtlSignals of struct type + interface with same signal structure if isinstance(src, InterfaceBase): if isinstance(dst, InterfaceBase): return dst._connectTo(src, exclude=exclude, fit=fit) assert not exclude, ("dst does not contain subinterfaces," " excluded should be already processed in this state", src, dst, exclude) if src is None: src = dst._dtype.from_py(None) else: src = toHVal(src) if fit: src = fitTo(src, dst) src = src._auto_cast(dst._dtype) return dst(src)