def __init__(self, scope, indent: int, createTmpVarFn, constCache=None): SerializerCtx.__init__(self, scope, indent, createTmpVarFn, constCache=constCache) self._valueWidthRequired = False
def _operand(cls, operand: Union[RtlSignal, Value], operator: OpDefinition, ctx: SerializerCtx): try: isTernaryOp = operand.hidden and operand.drivers[ 0].operator == AllOps.TERNARY except (AttributeError, IndexError): isTernaryOp = False if isTernaryOp: # rewrite ternary operator as if o = ctx.createTmpVarFn("tmpTernary", operand._dtype) cond, ifTrue, ifFalse = operand.drivers[0].operands if_ = If(cond) if_.ifTrue.append( Assignment(ifTrue, o, virtualOnly=True, parentStm=if_)) if_.ifFalse = [] if_.ifFalse.append( Assignment(ifFalse, o, virtualOnly=True, parentStm=if_)) if_._outputs.append(o) for obj in (cond, ifTrue, ifFalse): if isinstance(obj, RtlSignalBase): if_._inputs.append(obj) o.drivers.append(if_) operand = o s = cls.asHdl(operand, ctx) if isinstance(operand, RtlSignalBase): try: o = operand.singleDriver() if o.operator != operator and\ cls.opPrecedence[o.operator] <= cls.opPrecedence[operator]: return "(%s)" % s except Exception: pass return s
def IfContainer(cls, ifc: IfContainer, ctx: SerializerCtx): cond = cls.condAsHdl(ifc.cond, ctx) ifTrue = ifc.ifTrue if ifc.elIfs: # replace elifs with nested if statements ifFalse = [] topIf = IfContainer(ifc.cond, ifc.ifTrue, ifFalse) topIf._inputs = ifc._inputs topIf._outputs = ifc._outputs topIf._sensitivity = ifc._sensitivity for c, stms in ifc.elIfs: _ifFalse = [] lastIf = IfContainer(c, stms, _ifFalse) lastIf._inputs = ifc._inputs lastIf._outputs = ifc._outputs lastIf._sensitivity = ifc._sensitivity ifFalse.append(lastIf) ifFalse = _ifFalse if ifc.ifFalse is None: lastIf.ifFalse = [] else: lastIf.ifFalse = ifc.ifFalse return cls.IfContainer(topIf, ctx) else: ifFalse = ifc.ifFalse if ifFalse is None: ifFalse = [] childCtx = ctx.withIndent() outputInvalidateStms = [] for o in ifc._outputs: # [TODO] look up indexes indexes = None oa = Assignment(o._dtype.from_py(None), o, indexes, virtual_only=True, parentStm=ifc, is_completly_event_dependent=ifc. _is_completly_event_dependent) outputInvalidateStms.append(cls.stmAsHdl(oa, childCtx)) return ifTmpl.render( indent=getIndent(ctx.indent), indentNum=ctx.indent, cond=cond, outputInvalidateStms=outputInvalidateStms, ifTrue=tuple( map(lambda obj: cls.stmAsHdl(obj, childCtx), ifTrue)), ifFalse=tuple( map(lambda obj: cls.stmAsHdl(obj, childCtx), ifFalse)))
def Operator(cls, op: Operator, ctx: SerializerCtx): ops = op.operands o = op.operator op_str = cls._unaryOps.get(o, None) if op_str is not None: cancel_parenthesis = op_str[-1] == ")" return op_str % (cls._operand(ops[0], 0, op, False, cancel_parenthesis, ctx)) op_str = cls._binOps.get(o, None) if op_str is not None: res_t = op.result._dtype if isinstance(res_t, Bits) and res_t != BOOL: op0 = cls._as_Bits(ops[0], ctx) op1 = cls._as_Bits(ops[1], ctx) op = op.operator._evalFn(op0, op1).drivers[0] return cls._bin_op( op, op_str, ctx, expr_requires_parenthesis=op.operator != AllOps.CONCAT) if o == AllOps.CALL: return "%s(%s)" % ( cls.FunctionContainer(ops[0]), ", ".join( # operand i does not matter as thy are all in () map(lambda op: cls._operand(op, 1, o, False, True, ctx), ops[1:]))) elif o == AllOps.INDEX: op0, op1 = ops if isinstance(op0, RtlSignalBase) and isResultOfTypeConversion(op0): op0 = ctx.createTmpVarFn("tmpTypeConv", op0._dtype) op0.def_val = ops[0] # if the op0 is not signal or other index index operator it is extracted # as tmp variable op0_str = cls._operand(op0, 0, op, False, False, ctx) op1_str = cls._operand(ops[1], 1, op, False, True, ctx) if isinstance(op1._dtype, Bits) and op1._dtype != INT: sig = op1._dtype.signed if sig is None: op1_str = "UNSIGNED(%s)" % op1_str op1_str = "TO_INTEGER(%s)" % op1_str return "%s(%s)" % (op0_str, op1_str) elif o == AllOps.TERNARY: op0 = cls.condAsHdl([ops[0]], True, ctx) op1 = cls._operand(ops[1], 1, op, False, False, ctx) op2 = cls._operand(ops[2], 2, op, False, False, ctx) return "%s WHEN %s ELSE %s" % (op0, op1, op2) else: raise NotImplementedError("Do not know how to convert %s to vhdl" % (o))
def Operator(cls, op: Operator, ctx: SerializerCtx): # [TODO] no nested ternary in expressions like # ( '1' WHEN r = f ELSE '0' ) & "0" ops = op.operands o = op.operator op_str = cls._unaryOps.get(o, None) if op_str is not None: return op_str % (cls._operand(ops[0], o, ctx)) op_str = cls._binOps.get(o, None) if op_str is not None: return op_str % (cls._operand(ops[0], o, ctx), cls._operand(ops[1], o, ctx)) if o == AllOps.CALL: return "%s(%s)" % (cls.FunctionContainer(ops[0]), ", ".join( map(lambda op: cls._operand(op, o, ctx), ops[1:]))) elif o == AllOps.INDEX: assert len(ops) == 2 o1 = ops[0] if isinstance(o1, RtlSignalBase) and isResultOfTypeConversion(o1): o1 = ctx.createTmpVarFn("tmpTypeConv", o1._dtype) o1.defVal = ops[0] return "%s(%s)" % (cls.asHdl( o1, ctx).strip(), cls._operand(ops[1], o, ctx)) elif o == AllOps.TERNARY: return " ".join([ cls._operand(ops[1], o, ctx), "WHEN", cls.condAsHdl([ops[0]], True, ctx), "ELSE", cls._operand(ops[2], o, ctx) ]) elif o == AllOps.BitsToInt: assert len(ops) == 1 op = cls.asHdl(ops[0], ctx) if ops[0]._dtype.signed is None: op = "UNSIGNED(%s)" % op return "TO_INTEGER(%s)" % op elif o == AllOps.IntToBits: assert len(ops) == 1 resT = op.result._dtype op_str = cls.asHdl(ops[0], ctx) w = resT.bit_length() if resT.signed is None: return "STD_LOGIC_VECTOR(TO_UNSIGNED(%s, %d))" % (op_str, w) elif resT.signed: return "TO_UNSIGNED(%s, %d)" % (op_str, w) else: return "TO_UNSIGNED(%s, %d)" % (op_str, w) else: raise NotImplementedError("Do not know how to convert %s to vhdl" % (o))
def HWProcess(cls, proc: HWProcess, ctx: SerializerCtx): body = proc.statements assert body proc.name = ctx.scope.checkedName(proc.name, proc) sensitivityList = sorted( map(cls.sensitivityListItem, proc.sensitivityList)) childCtx = ctx.withIndent(2) _body = "\n".join([cls.stmAsHdl(stm, childCtx) for stm in body]) return processTmpl.render(hasConditions=arr_any( body, lambda stm: not isinstance(stm, Assignment)), name=proc.name, sensitivityList=sensitivityList, stmLines=[_body])
def _as_Bits(cls, val: Union[RtlSignal, Value], ctx: SerializerCtx): if val._dtype == BOOL: bit1_t = Bits(1) o = ctx.createTmpVarFn("tmpBool2std_logic", bit1_t) ifTrue, ifFalse = bit1_t.from_py(1), bit1_t.from_py(0) if_ = If(val) if_.ifTrue.append( Assignment(ifTrue, o, virtual_only=True, parentStm=if_)) if_.ifFalse = [] if_.ifFalse.append( Assignment(ifFalse, o, virtual_only=True, parentStm=if_)) if_._outputs.append(o) o.drivers.append(if_) return o else: assert isinstance(val._dtype, Bits), val._dtype return val
def _operand(cls, operand: Union[RtlSignal, Value], i: int, operator: Operator, expr_requires_parenthesis: bool, cancel_parenthesis: bool, ctx: SerializerCtx): # [TODO] if operand is concatenation and parent operator # is not concatenation operand should be extracted # as tmp variable # * maybe flatten the concatenations if operator.operator != AllOps.CONCAT\ and cls._operandIsAnotherOperand(operand)\ and operand.origin.operator == AllOps.CONCAT: tmpVar = ctx.createTmpVarFn("tmp_concat_", operand._dtype) tmpVar.def_val = operand # Assignment(tmpVar, operand, virtual_only=True) operand = tmpVar oper = operator.operator width = None if oper not in [AllOps.BitsAsUnsigned, AllOps.BitsAsVec, AllOps.BitsAsSigned] and\ oper is not AllOps.INDEX and\ operand._dtype == INT and\ operator.result is not None and\ not operator.result._dtype == INT: # has to lock width for o in operator.operands: try: bl = o._dtype.bit_length except AttributeError: bl = None if bl is not None: width = bl() break assert width is not None, (operator, operand) s = super()._operand(operand, i, operator, width is not None or expr_requires_parenthesis, width is None and cancel_parenthesis, ctx) if width is not None: return "%d'%s" % (width, s) else: return s
def _tmp_var_for_ternary(cls, val: RtlSignal, ctx: SerializerCtx): """ Optionaly convert boolean to std_logic_vector """ o = ctx.createTmpVarFn("tmpTernary", val._dtype) cond, ifTrue, ifFalse = val.drivers[0].operands if_ = If(cond) if_.ifTrue.append( Assignment(ifTrue, o, virtual_only=True, parentStm=if_)) if_.ifFalse = [] if_.ifFalse.append( Assignment(ifFalse, o, virtual_only=True, parentStm=if_)) if_._outputs.append(o) for obj in (cond, ifTrue, ifFalse): if isinstance(obj, RtlSignalBase): if_._inputs.append(obj) o.drivers.append(if_) return o
def IfContainer(cls, ifc: IfContainer, ctx: SerializerCtx): """ Srialize IfContainer instance """ childCtx = ctx.withIndent() def asHdl(statements): return [cls.asHdl(s, childCtx) for s in statements] try: cond = cls.condAsHdl(ifc.cond, True, ctx) except UnsupportedEventOpErr as e: cond = None if cond is None: assert not ifc.elIfs assert not ifc.ifFalse stmBuff = [cls.asHdl(s, ctx) for s in ifc.ifTrue] return "\n".join(stmBuff) elIfs = [] ifTrue = ifc.ifTrue ifFalse = ifc.ifFalse if ifFalse is None: ifFalse = [] for c, statements in ifc.elIfs: try: elIfs.append((cls.condAsHdl(c, True, ctx), asHdl(statements))) except UnsupportedEventOpErr as e: if len(ifc.elIfs) == 1 and not ifFalse: # register expression is in valid format and this # is just register with asynchronous reset or etc... ifFalse = statements else: raise e return cls.ifTmpl.render(indent=getIndent(ctx.indent), cond=cond, ifTrue=asHdl(ifTrue), elIfs=elIfs, ifFalse=asHdl(ifFalse))
def SwitchContainer(cls, sw: SwitchContainer, ctx: SerializerCtx): childCtx = ctx.withIndent(1) def asHdl(statements): return [cls.asHdl(s, childCtx) for s in statements] switchOn = cls.condAsHdl(sw.switchOn, False, ctx) cases = [] for key, statements in sw.cases: key = cls.asHdl(key, ctx) cases.append((key, asHdl(statements))) if sw.default: cases.append((None, asHdl(sw.default))) return cls.switchTmpl.render(indent=getIndent(ctx.indent), switchOn=switchOn, cases=cases)
def getBaseContext(cls): return SerializerCtx(cls.getBaseNameScope(), 0, None, None)