test_caller_bcd: refactor addg6s test
authorDmitry Selyutin <dmitry.selyutin@3mdeb.com>
Thu, 19 Aug 2021 15:40:32 +0000 (15:40 +0000)
committerDmitry Selyutin <dmitry.selyutin@3mdeb.com>
Thu, 19 Aug 2021 17:34:08 +0000 (17:34 +0000)
This patch should vastly simplify and speed up the addg6s test. Most
importantly, we drop half adders and full adders, making use of the
fact that Python uses big integers directly. Also, we don't bother
generating all posible products of BCD numbers; instead, we simply
resort to random number generator. Note, however, that we only check
the numbers that are correct from BCD point of view.

src/openpower/decoder/isa/test_caller_bcd.py

index d831e11a528bebd633f0df531503cd99616f8487..12b00b55288d7b343a062408c21370a8d54539e9 100644 (file)
@@ -1,9 +1,11 @@
 import itertools
+import random
 import re
 from nmigen import Module, Signal
 from nmigen.back.pysim import Simulator, Settle
 from nmutil.formaltest import FHDLTestCase
 import unittest
+
 from openpower.decoder.isa.caller import ISACaller
 from openpower.decoder.power_decoder import create_pdecode
 from openpower.decoder.power_decoder2 import (PowerDecode2)
@@ -316,73 +318,52 @@ class BCDTestCase(FHDLTestCase):
                 mapping[bcd] = dpd
         self.run_tst("cbcdtd", mapping)
 
-    @unittest.skip("slowpoke")
     def test_addg6s(self):
-        def half_adder(a, b):
-            (a, b) = map(bool, [a, b])
-            carry = a & b
-            sum = a ^ b
-            return (int(sum), int(carry))
-
-        def full_adder(a, b, c):
-            (a, b, c) = map(bool, [a, b, c])
-            (sum0, carry0) = half_adder(a, b)
-            (sum, carry1) = half_adder(sum0, c)
-            carry = (carry0 | carry1)
-            return (int(sum), int(carry))
-
-        def full_adder64(a, b):
-            sum = [0] * 64
-            carry = [0] * 64
-            (sum[0], carry[0]) = half_adder(a[0], b[0])
-            for bit in range(1, 64, 1):
-                (sum[bit], carry[bit]) = full_adder(a[bit], b[bit],
-                                                    carry[bit - 1])
-            return (sum + [carry[63]])
-
         def addg6s(a, b):
-            BIT = lambda value, bit: int(bool((value >> bit) & 1))
-            r64 = range(63, -1, -1)
-            a = list(reversed(list(map(lambda bit: BIT(a, bit), r64))))
-            b = list(reversed(list(map(lambda bit: BIT(b, bit), r64))))
-            sum = full_adder64(a, b)
+            def bits(value, bits):
+                lsb = [((value >> bit) & 1) for bit in range(bits, -1, -1)]
+                return list(reversed(lsb))
 
-            a_in = lambda bit: a[bit]
-            b_in = lambda bit: b[bit]
-            sum_with_carry = lambda bit: sum[bit]
+            a_in = bits(a, 64)
+            b_in = bits(b, 64)
+            sum_with_carry = bits((a + b), 65)
 
             addg6s = [0] * 64
-            for i in range(15):
+            for i in range(16):
                 lo = i * 4
                 hi = (i + 1) * 4
-                if (a_in(hi) ^ b_in(hi) ^ (sum_with_carry(hi) == 0)):
+                if (a_in[hi] ^ b_in[hi] ^ (sum_with_carry[hi] == 0)):
                     addg6s[lo + 3] = 0
                     addg6s[lo + 2] = 1
                     addg6s[lo + 1] = 1
                     addg6s[lo + 0] = 0
-            if sum_with_carry(64) == 0:
+            if sum_with_carry[64] == 0:
                 addg6s[63] = 0
                 addg6s[62] = 1
                 addg6s[61] = 1
                 addg6s[60] = 0
             return int("".join(map(str, reversed(addg6s))), 2)
 
-        cond = lambda item: item[0] < ADDG6S_PRODUCT_LIMIT
-        bcd = map(lambda digit: f"{digit:04b}", range(10))
-        product = enumerate(itertools.product(bcd, repeat=16))
-        sequences = (seq for (_, seq) in itertools.takewhile(cond, product))
-        numbers = [int("".join(seq), 2) for seq in sequences]
-        iregs = [0] * 32
-        for a in numbers:
-            for b in numbers:
-                rv = addg6s(a, b)
-                with self.subTest():
-                    iregs[2] = b
-                    iregs[1] = a
-                    lst = ["addg6s 0, 1, 2"]
-                    with Program(lst, bigendian=False) as program:
-                        sim = self.run_tst_program(program, iregs)
-                        self.assertEqual(sim.gpr(0), SelectableInt(rv, 64))
+        bcd = [f"{digit:04b}" for digit in range(10)]
+        rng10 = lambda: random.randrange(0, 10)
+        bcdrng = lambda: int("".join((bcd[rng10()] for _ in range(16))), 2)
+
+        lst = []
+        oregs = [0] * 32
+        iregs = [bcdrng() for _ in range(32)]
+        for gpr in range(31):
+            lst += [f"addg6s {gpr}, {gpr + 0}, {gpr + 1}"]
+            oregs[gpr] = addg6s(iregs[gpr + 0], iregs[gpr + 1])
+
+        for _ in range(16):
+            with self.subTest():
+                for line in lst:
+                    print(line)
+                with Program(lst, bigendian=False) as program:
+                    sim = self.run_tst_program(program, iregs)
+                    for gpr in range(31):
+                        self.assertEqual(sim.gpr(gpr),
+                            SelectableInt(oregs[gpr], 64))
 
     def run_tst_program(self, prog, initial_regs=[0] * 32):
         simulator = run_tst(prog, initial_regs, pdecode2=self.pdecode2)