diff --git a/tests/lib/base_testcase.py b/tests/lib/base_testcase.py index 89c4e5d..6c9d4b8 100644 --- a/tests/lib/base_testcase.py +++ b/tests/lib/base_testcase.py @@ -52,7 +52,7 @@ class BaseTestCase(unittest.TestCase): @property def rerun(self) -> bool: """ - Re-run wothout deleting and re-generating prior output directory. + Re-run without deleting and re-generating prior output directory. """ return self.request.config.getoption("--rerun") @@ -79,14 +79,14 @@ class BaseTestCase(unittest.TestCase): f.write(f"{k}: {repr(v)}\n") - def _export_regblock(self): + def export_regblock(self): """ Call the peakrdl_regblock exporter to generate the DUT """ this_dir = self.get_testcase_dir() if self.rdl_file: - rdl_file = self.rdl_file + rdl_file = os.path.join(this_dir, self.rdl_file) else: # Find any *.rdl file in testcase dir rdl_file = glob.glob(os.path.join(this_dir, "*.rdl"))[0] @@ -120,17 +120,21 @@ class BaseTestCase(unittest.TestCase): default_reset_async=self.default_reset_async, ) + def delete_run_dir(self) -> None: + run_dir = self.get_run_dir() + if os.path.exists(run_dir): + shutil.rmtree(run_dir) + def setUp(self) -> None: if self.rerun: return # Create fresh build dir run_dir = self.get_run_dir() - if os.path.exists(run_dir): - shutil.rmtree(run_dir) + self.delete_run_dir() pathlib.Path(run_dir).mkdir(parents=True, exist_ok=True) self._write_params() # Convert testcase RDL file --> SV - self._export_regblock() + self.export_regblock() diff --git a/tests/test_validation_errors/__init__.py b/tests/test_validation_errors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_validation_errors/external_ref.rdl b/tests/test_validation_errors/external_ref.rdl new file mode 100644 index 0000000..99778b6 --- /dev/null +++ b/tests/test_validation_errors/external_ref.rdl @@ -0,0 +1,15 @@ +addrmap sub { + reg { + field {} f; + } x; +}; + +addrmap top { + reg { + field {} f; + } x; + + sub sub; + + x.f->reset = sub.x.f; +}; diff --git a/tests/test_validation_errors/inconsistent_accesswidth.rdl b/tests/test_validation_errors/inconsistent_accesswidth.rdl new file mode 100644 index 0000000..9a3057b --- /dev/null +++ b/tests/test_validation_errors/inconsistent_accesswidth.rdl @@ -0,0 +1,9 @@ +addrmap top { + reg { + field {}f; + } x; + reg { + accesswidth = 16; + field {}f; + } y; +}; diff --git a/tests/test_validation_errors/multiple_unconditional_assigns.rdl b/tests/test_validation_errors/multiple_unconditional_assigns.rdl new file mode 100644 index 0000000..a087018 --- /dev/null +++ b/tests/test_validation_errors/multiple_unconditional_assigns.rdl @@ -0,0 +1,40 @@ +addrmap top { + reg { + field { + sw = rw; + hw = w; + singlepulse = true; + } a = 0; + field { + sw = rw; + hw = w; + singlepulse = true; + posedge intr; + stickybit = false; + } b = 0; + field { + sw = rw; + hw = w; + singlepulse = true; + negedge intr; + stickybit = false; + } c = 0; + field { + sw = rw; + hw = w; + singlepulse = true; + bothedge intr; + stickybit = false; + } d = 0; + } x; +}; + +/* +stickybit=false + intr posedge +stickybit=false + intr negedge +stickybit=false + intr bothedge +hw=w wel = false +singlepulse + + +*/ diff --git a/tests/test_validation_errors/sharedextbus.rdl b/tests/test_validation_errors/sharedextbus.rdl new file mode 100644 index 0000000..de14091 --- /dev/null +++ b/tests/test_validation_errors/sharedextbus.rdl @@ -0,0 +1,7 @@ +addrmap top { + sharedextbus; + + reg { + field {}f; + } x; +}; diff --git a/tests/test_validation_errors/testcase.py b/tests/test_validation_errors/testcase.py new file mode 100644 index 0000000..53d2dff --- /dev/null +++ b/tests/test_validation_errors/testcase.py @@ -0,0 +1,78 @@ +import io +import contextlib + +from systemrdl.messages import RDLCompileError + +from ..lib.base_testcase import BaseTestCase + +class TestValidationErrors(BaseTestCase): + def setUp(self) -> None: + # Stub usual pre-test setup + pass + + def tearDown(self): + # Delete any cruft that may get generated + self.delete_run_dir() + + def assert_validate_error(self, rdl_file: str, err_regex: str) -> None: + self.rdl_file = rdl_file + f = io.StringIO() + with contextlib.redirect_stderr(f): + with self.assertRaises(RDLCompileError): + self.export_regblock() + stderr = f.getvalue() + self.assertRegex(stderr, err_regex) + + + def test_unaligned_reg(self) -> None: + self.assert_validate_error( + "unaligned_reg.rdl", + "Unaligned registers are not supported. Address offset of instance 'x' must be a multiple of 4", + ) + + def test_unaligned_stride(self) -> None: + self.assert_validate_error( + "unaligned_stride.rdl", + "Unaligned registers are not supported. Address stride of instance array 'x' must be a multiple of 4", + ) + + def test_bad_external_ref(self) -> None: + self.assert_validate_error( + "external_ref.rdl", + "Property is assigned a reference that points to a component not internal to the regblock being exported", + ) + + def test_sharedextbus_not_supported(self) -> None: + self.assert_validate_error( + "sharedextbus.rdl", + "This exporter does not support enabling the 'sharedextbus' property yet", + ) + + def test_inconsistent_accesswidth(self) -> None: + self.assert_validate_error( + "inconsistent_accesswidth.rdl", + r"Multi-word registers that have an accesswidth \(16\) that are inconsistent with this regblock's CPU bus width \(32\) are not supported", + ) + + def test_unbuffered_wide_w_fields(self) -> None: + self.assert_validate_error( + "unbuffered_wide_fields.rdl", + "Software-writable field 'xf' shall not span" + " multiple software-accessible subwords. Consider enabling" + " write double-buffering", + ) + + def test_unbuffered_wide_r_fields(self) -> None: + self.assert_validate_error( + "unbuffered_wide_fields.rdl", + "The field 'yf' spans multiple software-accessible" + " subwords and is modified on-read, making it impossible to" + " access its value correctly. Consider enabling read" + " double-buffering.", + ) + + def test_multiple_unconditional_assigns(self) -> None: + self.assert_validate_error( + "multiple_unconditional_assigns.rdl", + "Field has multiple conflicting properties that unconditionally set its state", + ) diff --git a/tests/test_validation_errors/unaligned_reg.rdl b/tests/test_validation_errors/unaligned_reg.rdl new file mode 100644 index 0000000..c30dac2 --- /dev/null +++ b/tests/test_validation_errors/unaligned_reg.rdl @@ -0,0 +1,8 @@ +addrmap top { + default regwidth = 32; + default accesswidth = 32; + + reg { + field {}f; + } x @ 1; +}; diff --git a/tests/test_validation_errors/unaligned_stride.rdl b/tests/test_validation_errors/unaligned_stride.rdl new file mode 100644 index 0000000..da5fb24 --- /dev/null +++ b/tests/test_validation_errors/unaligned_stride.rdl @@ -0,0 +1,8 @@ +addrmap top { + default regwidth = 32; + default accesswidth = 32; + + reg { + field {}f; + } x[4] @ 0 += 5; +}; diff --git a/tests/test_validation_errors/unbuffered_wide_fields.rdl b/tests/test_validation_errors/unbuffered_wide_fields.rdl new file mode 100644 index 0000000..e349a9c --- /dev/null +++ b/tests/test_validation_errors/unbuffered_wide_fields.rdl @@ -0,0 +1,21 @@ +addrmap top { + reg { + regwidth = 64; + accesswidth = 32; + field { + sw=w; + hw=r; + } xf[64]; + } x; + + reg { + regwidth = 64; + accesswidth = 32; + field { + sw=r; + hw=w; + we; + onread=rclr; + } yf[64]; + } y; +};