add tests for carry/overflow calculation of addmeo/subfmeo
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 28 Oct 2022 22:06:25 +0000 (15:06 -0700)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 2 Jun 2023 18:51:16 +0000 (19:51 +0100)
the logic for computing carry/overflow in the simulator is likely broken...

the pseudocode may also need to be changed to add [1] * XLEN like in the
description of addme/subfme

src/openpower/test/alu/alu_cases.py

index bb8a21eea81f4a7128e6be3bb6b07209c23b6298..de2c65e2406c99158991129e94a7cc870062fccc 100644 (file)
@@ -199,6 +199,49 @@ class ALUTestCase(TestAccumulatorBase):
         self.add_case(Program(lst, bigendian),
                       initial_regs, initial_sprs, expected=e)
 
+    def case_addme_subfme_ca_propagation(self):
+        for flags in range(1 << 2):
+            ca = flags & 1
+            is_sub = (flags >> 1) & 1
+            if is_sub:
+                prog = Program(["subfmeo 3, 4"], bigendian)
+            else:
+                prog = Program(["addmeo 3, 4"], bigendian)
+            for i in range(-2, 3):
+                ra = i % 2 ** 64
+                with self.subTest(ra=hex(ra), ca=ca, is_sub=is_sub):
+                    initial_regs = [0] * 32
+                    initial_regs[4] = ra
+                    initial_sprs = {}
+                    xer = SelectableInt(0, 64)
+                    xer[XER_bits['CA']] = ca
+                    initial_sprs[special_sprs['XER']] = xer
+                    e = ExpectedState(pc=4)
+                    e.intregs[4] = ra
+                    rb = 2 ** 64 - 1  # add 0xfff...fff *not* -1
+                    expected = ca + rb
+                    expected32 = ca + (rb % 2 ** 32)
+                    inv_ra = ra
+                    if is_sub:
+                        # 64-bit bitwise not
+                        inv_ra = ~ra % 2 ** 64
+                    expected += inv_ra
+                    expected32 += inv_ra % 2 ** 32
+                    e.intregs[3] = expected % 2 ** 64
+                    ca = bool(expected >> 64)
+                    ca32 = bool(expected32 >> 32)
+                    e.ca = (ca32 << 1) | ca
+                    # use algorithm from microwatt's calc_ov
+                    # https://github.com/antonblanchard/microwatt/blob/5c6d57de3056bd08fdc1f656bc8656635a77512b/execute1.vhdl#L284
+                    axb = inv_ra ^ rb
+                    emsb = (expected >> 63) & 1
+                    ov = ca ^ emsb and not (axb >> 63) & 1
+                    e32msb = (expected32 >> 31) & 1
+                    ov32 = ca32 ^ e32msb and not (axb >> 31) & 1
+                    e.ov = (ov32 << 1) | ov
+                    self.add_case(prog, initial_regs, initial_sprs,
+                                  expected=e)
+
     def case_addze(self):
         insns = ["addze", "addze.", "addzeo", "addzeo."]
         for choice in insns: