mirror of
https://github.com/myhdl/myhdl.git
synced 2025-01-24 21:52:56 +08:00
Constant value inversion (~0x1, ~0x4523) not working in VHDL (#407)
* Add test for the inverting of a constant integer (~0x3, ~0x24 etc), this works in myhdl and verilog but fails in VHDL * In the cases where the value being inverted is a constant, calculate in the conversion stage the correct inversion value and store that, for a not on a signal name or a boolean there is no change * Rewrite code so that a not int looks like a not int in the VHDL and not the calculated result * Ignore the warning as it is a operational message not a testing message * Change ast.Constant to ast.Num, the latter was only introduced in python3.8, it will be deprecated * Rewrite code to be python version dependent, ast.Num was removed in favour of ast.Constant in 3.8
This commit is contained in:
parent
0c38f9441b
commit
1dd830fbfc
@ -913,20 +913,66 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
|
||||
|
||||
def visit_UnaryOp(self, node):
|
||||
# in python3 a negative Num is represented as an USub of a positive Num
|
||||
# Fix: restore python2 behavior by a shortcut: invert value of Num, inherit
|
||||
# Fix: restore python2 behavior by a shortcut: invert value of Constant, inherit
|
||||
# vhdl type from UnaryOp node, and visit the modified operand
|
||||
if isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Num):
|
||||
node.operand.n = -node.operand.n
|
||||
node.operand.vhd = node.vhd
|
||||
self.visit(node.operand)
|
||||
return
|
||||
pre, suf = self.inferCast(node.vhd, node.vhdOri)
|
||||
self.write(pre)
|
||||
self.write("(")
|
||||
self.write(opmap[type(node.op)])
|
||||
self.visit(node.operand)
|
||||
self.write(")")
|
||||
self.write(suf)
|
||||
if sys.version_info >= (3, 8, 0):
|
||||
if isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Constant):
|
||||
node.operand.n = -node.operand.n
|
||||
node.operand.vhd = node.vhd
|
||||
self.visit(node.operand)
|
||||
return
|
||||
|
||||
pre, suf = self.inferCast(node.vhd, node.vhdOri)
|
||||
if isinstance(node.op, ast.UAdd):
|
||||
op = ""
|
||||
else:
|
||||
op = opmap[type(node.op)]
|
||||
|
||||
if isinstance(node.operand, ast.Constant):
|
||||
self.write("(")
|
||||
self.write(op)
|
||||
self.write("(")
|
||||
self.write(pre)
|
||||
self.visit(node.operand)
|
||||
self.write(suf)
|
||||
self.write(")")
|
||||
self.write(")")
|
||||
else:
|
||||
self.write(pre)
|
||||
self.write("(")
|
||||
self.write(op)
|
||||
self.visit(node.operand)
|
||||
self.write(")")
|
||||
self.write(suf)
|
||||
else:
|
||||
if isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Num):
|
||||
node.operand.n = -node.operand.n
|
||||
node.operand.vhd = node.vhd
|
||||
self.visit(node.operand)
|
||||
return
|
||||
|
||||
pre, suf = self.inferCast(node.vhd, node.vhdOri)
|
||||
if isinstance(node.op, ast.UAdd):
|
||||
op = ""
|
||||
else:
|
||||
op = opmap[type(node.op)]
|
||||
|
||||
if isinstance(node.operand, ast.Num):
|
||||
self.write("(")
|
||||
self.write(op)
|
||||
self.write("(")
|
||||
self.write(pre)
|
||||
self.visit(node.operand)
|
||||
self.write(suf)
|
||||
self.write(")")
|
||||
self.write(")")
|
||||
else:
|
||||
self.write(pre)
|
||||
self.write("(")
|
||||
self.write(op)
|
||||
self.visit(node.operand)
|
||||
self.write(")")
|
||||
self.write(suf)
|
||||
|
||||
def visit_Attribute(self, node):
|
||||
if isinstance(node.ctx, ast.Store):
|
||||
@ -1125,8 +1171,12 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
|
||||
opening, closing = '', ''
|
||||
pre, suf = self.inferCast(node.vhd, node.vhdOri)
|
||||
# convert number argument to integer
|
||||
if isinstance(node.args[0], ast.Num):
|
||||
node.args[0].n = int(node.args[0].n)
|
||||
if sys.version_info >= (3, 8, 0):
|
||||
if isinstance(node.args[0], ast.Constant):
|
||||
node.args[0].n = int(node.args[0].n)
|
||||
else:
|
||||
if isinstance(node.args[0], ast.Num):
|
||||
node.args[0].n = int(node.args[0].n)
|
||||
elif inspect.isclass(f) and issubclass(f, intbv):
|
||||
pre, post = "", ""
|
||||
arg = node.args[0]
|
||||
@ -1296,8 +1346,12 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
|
||||
self.write(doc)
|
||||
return
|
||||
# skip extra semicolons
|
||||
if isinstance(expr, ast.Num):
|
||||
return
|
||||
if sys.version_info >= (3, 8, 0):
|
||||
if isinstance(expr, ast.Constant):
|
||||
return
|
||||
else:
|
||||
if isinstance(expr, ast.Num):
|
||||
return
|
||||
self.visit(expr)
|
||||
# ugly hack to detect an orphan "task" call
|
||||
if isinstance(expr, ast.Call) and hasattr(expr, 'tree'):
|
||||
|
@ -838,8 +838,12 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
|
||||
elif f is int:
|
||||
opening, closing = '', ''
|
||||
# convert number argument to integer
|
||||
if isinstance(node.args[0], ast.Num):
|
||||
node.args[0].n = int(node.args[0].n)
|
||||
if sys.version_info >= (3, 8, 0):
|
||||
if isinstance(node.args[0], ast.Constant):
|
||||
node.args[0].n = int(node.args[0].n)
|
||||
else:
|
||||
if isinstance(node.args[0], ast.Num):
|
||||
node.args[0].n = int(node.args[0].n)
|
||||
elif f in (intbv, modbv):
|
||||
self.visit(node.args[0])
|
||||
return
|
||||
@ -946,8 +950,12 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin):
|
||||
self.write(doc)
|
||||
return
|
||||
# skip extra semicolons
|
||||
if isinstance(expr, ast.Num):
|
||||
return
|
||||
if sys.version_info >= (3, 8, 0):
|
||||
if isinstance(expr, ast.Constant):
|
||||
return
|
||||
else:
|
||||
if isinstance(expr, ast.Num):
|
||||
return
|
||||
self.visit(expr)
|
||||
# ugly hack to detect an orphan "task" call
|
||||
if isinstance(expr, ast.Call) and hasattr(expr, 'tree'):
|
||||
@ -1600,8 +1608,12 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin):
|
||||
node.signed = node.operand.signed
|
||||
if isinstance(node.op, ast.USub):
|
||||
node.obj = int(-1)
|
||||
if isinstance(node.operand, ast.Num):
|
||||
node.signed = True
|
||||
if sys.version_info >= (3, 8, 0):
|
||||
if isinstance(node.operand, ast.Constant):
|
||||
node.signed = True
|
||||
else:
|
||||
if isinstance(node.operand, ast.Num):
|
||||
node.signed = True
|
||||
|
||||
def visit_Attribute(self, node):
|
||||
if isinstance(node.ctx, ast.Store):
|
||||
|
241
myhdl/test/conversion/general/test_unaryop.py
Normal file
241
myhdl/test/conversion/general/test_unaryop.py
Normal file
@ -0,0 +1,241 @@
|
||||
from myhdl import *
|
||||
import pytest
|
||||
|
||||
@block
|
||||
def notVector0(
|
||||
a,
|
||||
z,
|
||||
):
|
||||
|
||||
@always_comb
|
||||
def outputs():
|
||||
z.next = a & ~0x1
|
||||
|
||||
|
||||
return instances()
|
||||
|
||||
@block
|
||||
def notVector1(
|
||||
a,
|
||||
b,
|
||||
z,
|
||||
):
|
||||
|
||||
@always_comb
|
||||
def outputs():
|
||||
z.next = a & ~b
|
||||
|
||||
|
||||
return instances()
|
||||
|
||||
@block
|
||||
def notVector2(
|
||||
a,
|
||||
z,
|
||||
):
|
||||
|
||||
@always_comb
|
||||
def outputs():
|
||||
z.next = a & +0xfe
|
||||
|
||||
|
||||
return instances()
|
||||
|
||||
@block
|
||||
def notVector3(
|
||||
a,
|
||||
b,
|
||||
z,
|
||||
):
|
||||
|
||||
@always_comb
|
||||
def outputs():
|
||||
z.next = a & +b
|
||||
|
||||
|
||||
return instances()
|
||||
|
||||
@block
|
||||
def notVector4(
|
||||
a,
|
||||
z,
|
||||
):
|
||||
|
||||
@always_comb
|
||||
def outputs():
|
||||
z.next = a & -0x2
|
||||
|
||||
|
||||
return instances()
|
||||
|
||||
|
||||
@block
|
||||
def notVectorBench0(rev=0):
|
||||
|
||||
clk = Signal(bool(0))
|
||||
a = Signal(modbv(0)[8:])
|
||||
b = Signal(modbv(0)[8:])
|
||||
z = Signal(modbv(0)[8:])
|
||||
|
||||
@instance
|
||||
def clkgen():
|
||||
clk.next = 1
|
||||
for i in range(400):
|
||||
yield delay(10)
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def stimulus():
|
||||
a.next = 0x0
|
||||
if 3 == rev:
|
||||
b.next = 0xfe
|
||||
elif 5 == rev:
|
||||
b.next = 0x2
|
||||
else:
|
||||
b.next = 0x1
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
a.next = 0x0
|
||||
yield clk.posedge
|
||||
a.next = 0x1
|
||||
yield clk.posedge
|
||||
a.next = 0x2
|
||||
yield clk.posedge
|
||||
a.next = 0x3
|
||||
yield clk.posedge
|
||||
a.next = 0xff
|
||||
yield clk.posedge
|
||||
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
yield clk.posedge
|
||||
assert z == 0x0
|
||||
yield clk.posedge
|
||||
assert z == 0x0
|
||||
yield clk.posedge
|
||||
assert z == 0x2
|
||||
yield clk.posedge
|
||||
assert z == 0x2
|
||||
yield clk.posedge
|
||||
assert z == 0xfe
|
||||
yield clk.posedge
|
||||
|
||||
if 1 == rev:
|
||||
i_notVector = notVector1(a, b, z)
|
||||
elif 2 == rev:
|
||||
i_notVector = notVector2(a, z)
|
||||
elif 3 == rev:
|
||||
i_notVector = notVector3(a, b, z)
|
||||
elif 4 == rev:
|
||||
i_notVector = notVector4(a, z)
|
||||
else:
|
||||
i_notVector = notVector0(a, z)
|
||||
|
||||
|
||||
return instances()
|
||||
|
||||
def test_notVector0():
|
||||
sim = notVectorBench0(0)
|
||||
sim.run_sim()
|
||||
|
||||
def test_notVector0Inst():
|
||||
|
||||
clk = Signal(bool(0))
|
||||
a = Signal(modbv(0)[8:])
|
||||
z = Signal(modbv(0)[8:])
|
||||
|
||||
i_dut = notVector0(a, z)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:Signal is driven")
|
||||
def test_notVector0_convert():
|
||||
i_dut = notVectorBench0(0)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
#assert i_dut.verify_convert() == 0
|
||||
|
||||
def test_notVector1():
|
||||
sim = notVectorBench0(1)
|
||||
sim.run_sim()
|
||||
|
||||
def test_notVector1Inst():
|
||||
|
||||
clk = Signal(bool(0))
|
||||
a = Signal(modbv(0)[8:])
|
||||
b = Signal(modbv(0)[8:])
|
||||
z = Signal(modbv(0)[8:])
|
||||
|
||||
i_dut = notVector1(a, b, z)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
|
||||
|
||||
def test_notVector1_convert():
|
||||
i_dut = notVectorBench0(1)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
#assert i_dut.verify_convert() == 0
|
||||
|
||||
def test_notVector2():
|
||||
sim = notVectorBench0(2)
|
||||
sim.run_sim()
|
||||
|
||||
def test_notVector2Inst():
|
||||
|
||||
clk = Signal(bool(0))
|
||||
a = Signal(modbv(0)[8:])
|
||||
z = Signal(modbv(0)[8:])
|
||||
|
||||
i_dut = notVector2(a, z)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:Signal is driven")
|
||||
def test_notVector2_convert():
|
||||
i_dut = notVectorBench0(2)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
#assert i_dut.verify_convert() == 0
|
||||
|
||||
def test_notVector3():
|
||||
sim = notVectorBench0(3)
|
||||
sim.run_sim()
|
||||
|
||||
def test_notVector3Inst():
|
||||
|
||||
clk = Signal(bool(0))
|
||||
a = Signal(modbv(0)[8:])
|
||||
b = Signal(modbv(0)[8:])
|
||||
z = Signal(modbv(0)[8:])
|
||||
|
||||
i_dut = notVector3(a, b, z)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
|
||||
|
||||
def test_notVector3_convert():
|
||||
i_dut = notVectorBench0(3)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
#assert i_dut.verify_convert() == 0
|
||||
|
||||
def test_notVector4():
|
||||
sim = notVectorBench0(4)
|
||||
sim.run_sim()
|
||||
|
||||
def test_notVector4Inst():
|
||||
|
||||
clk = Signal(bool(0))
|
||||
a = Signal(modbv(0)[8:])
|
||||
z = Signal(modbv(0)[8:])
|
||||
|
||||
i_dut = notVector4(a, z)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:Signal is driven")
|
||||
def test_notVector4_convert():
|
||||
i_dut = notVectorBench0(4)
|
||||
assert i_dut.analyze_convert() == 0
|
||||
#assert i_dut.verify_convert() == 0
|
||||
|
@ -6,6 +6,7 @@ from random import randrange
|
||||
import myhdl
|
||||
from myhdl import *
|
||||
from myhdl.conversion import verify
|
||||
import pytest
|
||||
|
||||
|
||||
NRTESTS = 10
|
||||
@ -187,6 +188,7 @@ def binaryBench(Ll, Ml, Lr, Mr):
|
||||
return binops, stimulus, check
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:Signal is not driven")
|
||||
def testBinaryOps():
|
||||
for Ll, Ml, Lr, Mr in (
|
||||
(-254, 236, 0, 4),
|
||||
|
Loading…
x
Reference in New Issue
Block a user