add test_caller_bcd_full.py to fully test all edge cases missed by test_caller_bcd.py
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 7 Sep 2021 05:35:07 +0000 (22:35 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 7 Sep 2021 05:35:07 +0000 (22:35 -0700)
src/openpower/decoder/isa/test_caller_bcd_full.py [new file with mode: 0644]

diff --git a/src/openpower/decoder/isa/test_caller_bcd_full.py b/src/openpower/decoder/isa/test_caller_bcd_full.py
new file mode 100644 (file)
index 0000000..566b0e4
--- /dev/null
@@ -0,0 +1,106 @@
+from nmutil.formaltest import FHDLTestCase
+import unittest
+from openpower.decoder.power_decoder import create_pdecode
+from openpower.decoder.power_decoder2 import (PowerDecode2)
+from openpower.simulator.program import Program
+from openpower.decoder.selectable_int import SelectableInt
+from openpower.decoder.isa.test_runner import run_tst
+import power_instruction_analyzer as pia
+from hashlib import sha256
+
+
+class BCDFullTestCase(FHDLTestCase):
+    """test full arbitrary bit patterns, including invalid BCD (not
+    supported by above reference code), against power-instruction-analyzer"""
+
+    TEST_INDEX_COUNT = 8
+    pdecode2 = None
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        if BCDFullTestCase.pdecode2 is None:
+            pdecode = create_pdecode()
+            BCDFullTestCase.pdecode2 = PowerDecode2(pdecode)
+
+    def hash(self, v):
+        return int.from_bytes(
+            sha256(bytes(str(v), encoding='ascii')).digest(),
+            byteorder='little'
+        )
+
+    def addg6s_tst_cases(self):
+        mask = (1 << 64) - 1
+        for i in range(1024):
+            v = self.hash(i)
+            yield (v & mask, (v >> 64) & mask)
+
+    def bcd_dpd_tst_cases(self):
+        mask = (1 << 64) - 1
+        limit = 1 << 12
+        for i in range(limit):
+            v = self.hash(i)
+            v &= mask  # mask to 64-bits
+            # replace lower bits with `i` to ensure we cover all patterns
+            v &= ~(limit - 1)
+            v |= i
+            yield (v,)
+
+    def run_cases(self, test_index, test_cases, instr, arg_in_count):
+        pia_func = getattr(pia, instr.replace('.', '_'))
+        lst = []
+        for i in range(0, 32, arg_in_count):
+            input_args = ', '.join(str(i + j)
+                                   for j in range(arg_in_count))
+            lst.append(f"{instr} {i}, {input_args}")
+        with Program(lst, bigendian=False) as program:
+            pass
+        test_cases = list(test_cases)
+        outer_start_index = test_index \
+            * len(test_cases) // self.TEST_INDEX_COUNT
+        outer_end_index = (test_index + 1) \
+            * len(test_cases) // self.TEST_INDEX_COUNT
+        for outer_index in range(outer_start_index, outer_end_index, len(lst)):
+            inner_start_index = outer_index
+            inner_end_index = min(outer_end_index,
+                                  inner_start_index + len(lst))
+            inner_range = range(inner_start_index, inner_end_index)
+            initial_regs = [0 for i in range(32)]
+            expected_outputs = initial_regs.copy()
+            reg_num = 0
+            for i in inner_range:
+                for j in range(arg_in_count):
+                    v = test_cases[i][j]
+                    initial_regs[reg_num + j] = v
+                    expected_outputs[reg_num + j] = v
+                inputs = pia.InstructionInput(ra=test_cases[i][0])
+                if 1 < arg_in_count:
+                    inputs.rb = test_cases[i][1]
+                outputs = pia_func(inputs)
+                expected_outputs[reg_num] = outputs.rt
+                reg_num += arg_in_count
+            with self.subTest(inner_range=inner_range):
+                sim = run_tst(program, initial_regs, pdecode2=self.pdecode2)
+                for reg_num in range(32):
+                    with self.subTest(reg_num=reg_num):
+                        self.assertEqual(sim.gpr(reg_num),
+                                         SelectableInt(expected_outputs[reg_num], 64))
+        pass
+
+    def tst_addg6s(self, test_index):
+        self.run_cases(test_index, self.addg6s_tst_cases(), 'addg6s', 2)
+
+    def tst_cdtbcd(self, test_index):
+        self.run_cases(test_index, self.bcd_dpd_tst_cases(), 'cdtbcd', 1)
+
+    def tst_cbcdtd(self, test_index):
+        self.run_cases(test_index, self.bcd_dpd_tst_cases(), 'cbcdtd', 1)
+
+
+for i in range(BCDFullTestCase.TEST_INDEX_COUNT):
+    for j in 'addg6s', 'cdtbcd', 'cbcdtd':
+        def tst_fn(self):
+            getattr(self, f"tst_{j}")(i)
+        setattr(BCDFullTestCase, f"test_{j}_{i}", tst_fn)
+
+if __name__ == "__main__":
+    unittest.main()