9 from contextlib
import contextmanager
11 from ..hdl
.ast
import *
12 from ..back
import rtlil
15 __all__
= ["FHDLTestCase"]
18 class FHDLTestCase(unittest
.TestCase
):
19 def assertRepr(self
, obj
, repr_str
):
20 obj
= Statement
.wrap(obj
)
21 def prepare_repr(repr_str
):
22 repr_str
= re
.sub(r
"\s+", " ", repr_str
)
23 repr_str
= re
.sub(r
"\( (?=\()", "(", repr_str
)
24 repr_str
= re
.sub(r
"\) (?=\))", ")", repr_str
)
25 return repr_str
.strip()
26 self
.assertEqual(prepare_repr(repr(obj
)), prepare_repr(repr_str
))
29 def assertRaises(self
, exception
, msg
=None):
30 with
super().assertRaises(exception
) as cm
:
33 # WTF? unittest.assertRaises is completely broken.
34 self
.assertEqual(str(cm
.exception
), msg
)
37 def assertRaisesRegex(self
, exception
, regex
=None):
38 with
super().assertRaises(exception
) as cm
:
41 # unittest.assertRaisesRegex also seems broken...
42 self
.assertRegex(str(cm
.exception
), regex
)
45 def assertWarns(self
, category
, msg
=None):
46 with warnings
.catch_warnings(record
=True) as warns
:
48 self
.assertEqual(len(warns
), 1)
49 self
.assertEqual(warns
[0].category
, category
)
51 self
.assertEqual(str(warns
[0].message
), msg
)
53 def assertFormal(self
, spec
, mode
="bmc", depth
=1):
54 caller
, *_
= traceback
.extract_stack(limit
=2)
55 spec_root
, _
= os
.path
.splitext(caller
.filename
)
56 spec_dir
= os
.path
.dirname(spec_root
)
57 spec_name
= "{}_{}".format(
58 os
.path
.basename(spec_root
).replace("test_", "spec_"),
59 caller
.name
.replace("test_", "")
62 # The sby -f switch seems not fully functional when sby is reading from stdin.
63 if os
.path
.exists(os
.path
.join(spec_dir
, spec_name
)):
64 shutil
.rmtree(os
.path
.join(spec_dir
, spec_name
))
67 # A mix of BMC and k-induction, as per personal communication with Clifford Wolf.
68 script
= "setattr -unset init w:* a:nmigen.sample_reg %d"
73 config
= textwrap
.dedent("""\
93 rtlil
=rtlil
.convert(spec
.get_fragment("formal"))
95 with subprocess
.Popen(["sby", "-f", "-d", spec_name
], cwd
=spec_dir
,
96 universal_newlines
=True,
97 stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
) as proc
:
98 stdout
, stderr
= proc
.communicate(config
)
99 if proc
.returncode
!= 0:
100 self
.fail("Formal verification failed:\n" + stdout
)