1
0
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:
Dave Keeshan 2023-02-03 17:00:11 +00:00 committed by GitHub
parent 0c38f9441b
commit 1dd830fbfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 332 additions and 23 deletions

View File

@ -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'):

View File

@ -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):

View 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

View File

@ -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),