from operator import floordiv, add, sub, inv, mod, mul, ne, and_, or_, \
xor, gt, ge, lt, le, getitem, neg
from hwt.doc_markers import internal
from hwt.hdl.types.defs import INT, SLICE
from hwt.hdl.value import HValue
[docs]def _getVal(v):
while not isinstance(v, HValue):
v = v._val
return v
[docs]class OpDefinition():
"""
Operator definition
:ivar ~.id: name of operator
:ivar ~._evalFn: function which evaluates operands
"""
[docs] def __init__(self, evalFn, allowsAssignTo=False):
self.id = None # assigned automatically in AllOps
self._evalFn = evalFn
self.allowsAssignTo = allowsAssignTo
def __eq__(self, other):
return type(self) == type(other) and self.id == other.id
@internal
def __hash__(self):
return hash(self.id)
[docs] def eval(self, operator, simulator=None):
"""Load all operands and process them by self._evalFn"""
operands = [_getVal(o) for o in operator.operands]
return self._evalFn(*operands)
def __repr__(self):
return f"<{self.__class__.__name__:s} {self.id:s}>"
[docs]def isEventDependentOp(operator):
return operator in (AllOps.RISING_EDGE, AllOps.FALLING_EDGE)
[docs]def onRisingEdgeFn(a):
return a._onRisingEdge()
[docs]def onFallingEdgeFn(a):
return a._onFallingEdge()
[docs]def dotOpFn(a, name):
return getattr(a, name)
# [TODO] downto / to are relict of vhdl and should be replaced with slice
[docs]def downtoFn(a, b):
return SLICE.from_py(slice(a, b, -1))
[docs]def toFn(a, b):
return SLICE.from_py(slice(a, b, 1))
[docs]def concatFn(a, b):
return a._concat(b)
[docs]def power(base, exp):
return base ** exp
[docs]def eqFn(a, b):
return a._eq(b)
[docs]def ternaryFn(a, b, c):
return a._ternary(b, c)
[docs]def callFn(fn, *operands, **kwargs):
return fn(*operands, **kwargs)
[docs]def bitsToIntFn(a):
return a._auto_cast(INT)
[docs]def intToBitsFn(a, t):
return a._auto_cast(t)
[docs]def bitsAsSignedFn(a):
return a._signed()
[docs]def bitsAsUnsignedFn(a):
return a._unsigned()
[docs]def bitsAsVec(a):
return a._vec()
[docs]class AllOps():
"""
:attention: Remember that and operator "and" is & and "or" is \|, "and"
and "or" can not be used because they can not be overloaded
:attention: These are operators of internal AST,
they are not equal to verilog or vhdl operators
"""
RISING_EDGE = OpDefinition(onRisingEdgeFn) # unnecessary
FALLING_EDGE = OpDefinition(onFallingEdgeFn) # unnecessary
MINUS_UNARY = OpDefinition(neg)
DIV = OpDefinition(floordiv)
ADD = OpDefinition(add)
SUB = OpDefinition(sub)
POW = OpDefinition(power)
MOD = OpDefinition(mod)
MUL = OpDefinition(mul)
NOT = OpDefinition(inv, allowsAssignTo=True)
XOR = OpDefinition(xor)
AND = OpDefinition(and_)
OR = OpDefinition(or_)
DOT = OpDefinition(dotOpFn)
DOWNTO = OpDefinition(downtoFn)
TO = OpDefinition(toFn)
CONCAT = OpDefinition(concatFn, allowsAssignTo=True)
EQ = OpDefinition(eqFn)
NE = OpDefinition(ne)
GT = OpDefinition(gt)
GE = OpDefinition(ge)
LT = OpDefinition(lt)
LE = OpDefinition(le)
INDEX = OpDefinition(getitem, allowsAssignTo=True)
TERNARY = OpDefinition(ternaryFn)
CALL = OpDefinition(callFn)
BitsAsSigned = OpDefinition(bitsAsSignedFn, allowsAssignTo=True)
BitsAsUnsigned = OpDefinition(bitsAsUnsignedFn, allowsAssignTo=True)
BitsAsVec = OpDefinition(bitsAsVec, allowsAssignTo=True)
for a_name in dir(AllOps):
o = getattr(AllOps, a_name)
if isinstance(o, OpDefinition):
o.id = a_name
CAST_OPS = (AllOps.BitsAsVec, AllOps.BitsAsSigned, AllOps.BitsAsUnsigned)
BITWISE_OPS = (AllOps.NOT, AllOps.XOR, AllOps.AND, AllOps.OR)
COMPARE_OPS = (AllOps.EQ, AllOps.NE, AllOps.GT, AllOps.GE, AllOps.LT, AllOps.LE)
# change of compare operator on operand order swap
CMP_OP_SWAP = {
AllOps.EQ: AllOps.EQ,
AllOps.NE: AllOps.NE,
AllOps.GT: AllOps.LT,
AllOps.GE: AllOps.LE,
AllOps.LT: AllOps.GT,
AllOps.LE: AllOps.GE,
}
CMP_OPS_NEG = {
AllOps.EQ: AllOps.NE,
AllOps.NE: AllOps.EQ,
AllOps.GT: AllOps.LE,
AllOps.GE: AllOps.LT,
AllOps.LT: AllOps.GE,
AllOps.LE: AllOps.GT,
}
# always commutative operators for which order of operands does not matter
ALWAYS_COMMUTATIVE_OPS = (AllOps.EQ, AllOps.NE, AllOps.XOR, AllOps.AND, AllOps.OR, AllOps.ADD, AllOps.MUL)
# always commutative associative operators for which order of operands in expression tree does not matter
ALWAYS_ASSOCIATIVE_COMMUTATIVE_OPS = (AllOps.XOR, AllOps.AND, AllOps.OR, AllOps.ADD, AllOps.MUL)
EVENT_OPS = (AllOps.RISING_EDGE, AllOps.FALLING_EDGE)