from hdlConvertorAst.hdlAst._expr import HdlOpType, HdlValueId, HdlValueInt, \
HdlAll, HdlOp, HdlOthers
from hdlConvertorAst.py_ver_compatibility import is_str
from hdlConvertorAst.to.common import ToHdlCommon, ASSOCIATIVITY
from hdlConvertorAst.to.hdlUtils import iter_with_last, Indent
from copy import copy
L = ASSOCIATIVITY.L_TO_R
R = ASSOCIATIVITY.R_TO_L
# https://www.csee.umbc.edu/portal/help/VHDL/operator.html
[docs]class ToVhdl2008Expr(ToHdlCommon):
GENERIC_UNARY_OPS = copy(ToHdlCommon.GENERIC_UNARY_OPS)
GENERIC_UNARY_OPS.update({
HdlOpType.NEG: "NOT ",
HdlOpType.NEG_LOG: "NOT ",
HdlOpType.RANGE: "RANGE ", # used in HdlPhysicalDef
})
BITWISE_BIN_OPS = {
HdlOpType.AND, HdlOpType.AND_LOG,
HdlOpType.OR, HdlOpType.OR_LOG,
HdlOpType.XOR, HdlOpType.NAND,
HdlOpType.NOR, HdlOpType.XNOR
}
GENERIC_BIN_OPS = {
HdlOpType.AND: " AND ",
HdlOpType.AND_LOG: " AND ",
HdlOpType.OR: " OR ",
HdlOpType.OR_LOG: " OR ",
HdlOpType.DIV: " / ",
HdlOpType.MOD: " MOD ",
HdlOpType.REM: " REM ",
HdlOpType.POW: " ** ",
HdlOpType.NAND: " NAND ",
HdlOpType.NOR: " NOR ",
HdlOpType.XOR: " XOR ",
HdlOpType.XNOR: " XNOR ",
HdlOpType.EQ: ' = ',
HdlOpType.NE: " /= ",
HdlOpType.EQ_MATCH: ' ?= ',
HdlOpType.NE_MATCH: ' ?/= ',
HdlOpType.LT_MATCH: ' ?< ',
HdlOpType.LE_MATCH: ' ?<= ',
HdlOpType.GT_MATCH: ' ?> ',
HdlOpType.GE_MATCH: ' ?>= ',
HdlOpType.TO: " TO ",
HdlOpType.DOWNTO: " DOWNTO ",
HdlOpType.ARROW: " => ",
HdlOpType.MAP_ASSOCIATION: " => ",
HdlOpType.RANGE: " RANGE ",
HdlOpType.CONCAT: " & ",
HdlOpType.ROL: " ROL ",
HdlOpType.ROR: " ROR ",
HdlOpType.SLA: " SLA ",
HdlOpType.SRA: " SRA ",
HdlOpType.SLL: " SLL ",
HdlOpType.SRL: " SRL ",
HdlOpType.UNIT_SPEC: " ",
}
EQ_NEQ_OPS = (
HdlOpType.EQ,
HdlOpType.NE
)
GENERIC_BIN_OPS.update(ToHdlCommon.GENERIC_BIN_OPS)
NUM_BASES = {
2: "",
8: "O",
16: "X",
256: "", # 'X' literals
}
OP_PRECEDENCE = {
HdlOpType.UNIT_SPEC: (0, L),
HdlOpType.DOT: (1, L),
HdlOpType.CALL: (1, L),
HdlOpType.INDEX: (1, L),
HdlOpType.RISING: (1, L),
HdlOpType.FALLING: (1, L),
HdlOpType.APOSTROPHE: (1, L),
HdlOpType.POW: (2, R),
HdlOpType.ABS: (2, L),
HdlOpType.NEG: (2, R),
HdlOpType.NEG_LOG: (2, R),
HdlOpType.MUL: (3, L),
HdlOpType.DIV: (3, L),
HdlOpType.MOD: (3, L),
HdlOpType.REM: (3, L),
HdlOpType.PLUS_UNARY: (4, R),
HdlOpType.MINUS_UNARY: (4, R),
HdlOpType.CONCAT: (5, L),
HdlOpType.ADD: (5, L),
HdlOpType.SUB: (5, L),
HdlOpType.SLL: (6, L),
HdlOpType.SRL: (6, L),
HdlOpType.SLA: (6, L),
HdlOpType.SRA: (6, L),
HdlOpType.ROL: (6, L),
HdlOpType.ROR: (6, L),
HdlOpType.EQ: (7, L),
HdlOpType.NE: (7, L),
HdlOpType.GT: (7, L),
HdlOpType.LT: (7, L),
HdlOpType.GE: (7, L),
HdlOpType.LE: (7, L),
HdlOpType.EQ_MATCH: (7, L),
HdlOpType.NE_MATCH: (7, L),
HdlOpType.LT_MATCH: (7, L),
HdlOpType.LE_MATCH: (7, L),
HdlOpType.GT_MATCH: (7, L),
HdlOpType.GE_MATCH: (7, L),
HdlOpType.AND: (8, L),
HdlOpType.OR: (8, L),
HdlOpType.NAND: (8, ASSOCIATIVITY.NONE),
HdlOpType.NOR: (8, ASSOCIATIVITY.NONE),
HdlOpType.XOR: (8, L),
HdlOpType.XNOR: (8, ASSOCIATIVITY.NONE),
HdlOpType.DOWNTO: (9, L),
HdlOpType.TO: (9, L),
HdlOpType.TERNARY: (9, R),
HdlOpType.RANGE: (10, L),
HdlOpType.ARROW: (11, L),
HdlOpType.MAP_ASSOCIATION: (11, L),
}
[docs] def visit_HdlValueInt(self, o):
w = self.out.write
v = o.val
bits = o.bits
if is_str(v):
v = v.upper()
if o.base == 256:
w("'%s'" % v)
else:
w('%s"%s"' % (self.NUM_BASES[o.base], v))
return
if bits is None:
if o.base is not None:
b = self.NUM_BASES[o.base]
if o.base == 256:
w("'%d'" % v)
elif o.base == 16:
w('%s"%X"' % (b, v))
elif o.base == 8:
w('%s"%o"' % (b, v))
elif o.base == 2:
w('{0}"{1:b}"'.format(b, v))
else:
raise NotImplementedError(o.base)
else:
w(str(v))
return
elif bits % 8 == 0:
f = 'X"{0:0%dx}"' % (bits / 8)
else:
f = '"{0:0%db}"' % (bits)
w(f.format(v))
[docs] def _visit_operand_parentheses_extra_check(self, op_my, precedence_my, asoc_my,
op_parent, precedence_parent, asoc_parent,
left, right):
if super(ToVhdl2008Expr, self)._visit_operand_parentheses_extra_check(
op_my, precedence_my, asoc_my,
op_parent, precedence_parent, asoc_parent, left, right):
return True
elif op_my in self.BITWISE_BIN_OPS and\
op_parent in self.BITWISE_BIN_OPS and\
op_my != op_parent:
return True
else:
return False
[docs] def _visit_operand(self, operand, i,
parent,
expr_requires_parenthesis,
cancel_parenthesis):
if parent.fn in self.EQ_NEQ_OPS and isinstance(operand, HdlOp) and operand.fn in self.EQ_NEQ_OPS:
# handle the case (a = b) = (c = d) where to boolean conversion is applied during a = b evaluation
expr_requires_parenthesis = True
return ToHdlCommon._visit_operand(self, operand, i, parent, expr_requires_parenthesis, cancel_parenthesis)
[docs] def visit_HdlOp(self, o):
"""
:type o: HdlOp
"""
fn = o.ops[0]
if fn == HdlValueId("assert"):
self.visit_assert(o.ops[1:])
return
elif fn == HdlValueId("report"):
self.visit_report(o.ops[1:])
return
w = self.out.write
op = o.fn
if op == HdlOpType.RISING:
w("RISING_EDGE(")
self.visit_iHdlExpr(o.ops[0])
w(")")
elif op == HdlOpType.FALLING:
w("FALLING_EDGE(")
self.visit_iHdlExpr(o.ops[0])
w(")")
elif op == HdlOpType.INDEX or op == HdlOpType.CALL:
self._visit_operand(o.ops[0], 0, o, False, False)
w("(")
for isLast, (o_i, _o) in iter_with_last(enumerate(o.ops[1:])):
self._visit_operand(_o, o_i + 1, o, False, True)
if not isLast:
w(", ")
w(")")
elif op == HdlOpType.TERNARY:
has_3_ops = len(o.ops) == 3
if has_3_ops:
cond, o0, o1 = o.ops
else:
cond, o0 = o.ops
self._visit_operand(o0, 1, o, True, False)
w(" WHEN ")
self._visit_operand(cond, 0, o, True, False)
if has_3_ops:
if isinstance(o1, HdlOp) and o1.fn == HdlOpType.TERNARY:
w(" ELSE\n")
self.visit_iHdlExpr(o1) # must not have parenthesis
else:
w(" ELSE ")
self._visit_operand(o1, 2, o, False, False)
elif op == HdlOpType.APOSTROPHE:
self._visit_operand(o.ops[0], 0, o, True, False)
w("'")
args = o.ops[1]
if isinstance(args, list):
self.visit_iHdlExpr(args)
elif isinstance(args, HdlValueId):
# normal attribute
self.visit_iHdlExpr(args)
else:
w("(")
self._visit_operand(args, 0, o, False, True)
w(")")
elif op == HdlOpType.ABS:
w("ABS(")
self.visit_iHdlExpr(o.ops[0])
w(")")
elif op == HdlOpType.DEFINE_RESOLVER:
assert self.in_typedef
self.visit_iHdlExpr(o.ops[0])
w(" ")
self.visit_iHdlExpr(o.ops[1])
else:
return ToHdlCommon.visit_HdlOp(self, o)
[docs] def visit_str(self, o):
"""
:type o: str
"""
w = self.out.write
if o == "":
w('""')
else:
ESCAPES = {
'\n': 'LF\n',
'\c': 'CR'
}
CONC = self.GENERIC_BIN_OPS[HdlOpType.CONCAT]
first = True
in_string_lit = False
for c in o:
esc = ESCAPES.get(c, None)
if esc is None:
if not in_string_lit:
if not first:
# first character after escape sequence
w(CONC)
w('"') # string start "
in_string_lit = True
# character inside ""
w(c)
else:
if not first:
if in_string_lit:
w('"') # string end "
# escape sequence behind string
w(CONC)
in_string_lit = False
# escape name
w(esc)
first = False
if in_string_lit:
w('"') # string end "
[docs] def visit_iHdlExpr(self, expr):
w = self.out.write
if expr is HdlAll:
w("ALL")
elif expr is HdlOthers:
w("OTHERS")
elif expr is None:
if self.in_typedef:
w("<>")
else:
w("OPEN")
elif is_str(expr):
self.visit_str(expr)
elif isinstance(expr, list):
with_nl = len(expr) > 3
if with_nl:
w("(\n")
else:
w("(")
with Indent(self.out):
for is_last, elem in iter_with_last(expr):
self.visit_iHdlExpr(elem)
if not is_last:
if with_nl:
w(",\n")
else:
w(", ")
w(")")
else:
ToHdlCommon.visit_iHdlExpr(self, expr)