add cut/paste copy of strncpy example as basis for pospopcount
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 21 Nov 2023 12:39:28 +0000 (12:39 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 1 Dec 2023 14:02:55 +0000 (14:02 +0000)
https://bugs.libre-soc.org/show_bug.cgi?id=672

src/openpower/decoder/isa/test_caller_svp64_pospopcount.py [new file with mode: 0644]

diff --git a/src/openpower/decoder/isa/test_caller_svp64_pospopcount.py b/src/openpower/decoder/isa/test_caller_svp64_pospopcount.py
new file mode 100644 (file)
index 0000000..dbefe22
--- /dev/null
@@ -0,0 +1,143 @@
+"""Implementation of chacha20 core in SVP64
+Copyright (C) 2022,2023 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+Licensed under the LGPLv3+
+Funded by NLnet NGI-ASSURE under EU grant agreement No 957073.
+* https://nlnet.nl/project/LibreSOC-GigabitRouter/
+* https://bugs.libre-soc.org/show_bug.cgi?id=965
+* https://libre-soc.org/openpower/sv/cookbook/pospopcount/
+"""
+
+import unittest
+from copy import deepcopy
+
+from nmutil.formaltest import FHDLTestCase
+from openpower.decoder.isa.test_caller import run_tst
+from openpower.decoder.selectable_int import SelectableInt
+from openpower.simulator.program import Program
+from openpower.insndb.asm import SVP64Asm
+
+
+def write_byte(mem, addr, val):
+    addr, offs = (addr // 8)*8, (addr % 8)*8
+    mask = (0xff << offs)
+    value = mem.get(addr, 0) & ~mask
+    value = value | (val << offs)
+    mem[addr] = value & 0xffff_ffff_ffff_ffff
+
+
+
+class PosPopCountTestCase(FHDLTestCase):
+
+    def _check_regs(self, sim, expected):
+        for i in range(32):
+            self.assertEqual(sim.gpr(i), SelectableInt(expected[i], 64))
+
+    def test_sv_load_store_strncpy(self):
+        """>>> lst = [
+                    ]
+
+        strncpy using post-increment ld/st, sv.bc, and data-dependent ffirst.
+        note that /lf (Load-Fault) mode is not set in this example when it
+        should be. however implementing Load-Fault in ISACaller is tricky
+        (requires implementing multiple hardware models)
+        """
+        maxvl = 4
+        lst = SVP64Asm(
+            [
+                "mtspr 9, 3",                   # move r3 to CTR
+                "addi 0,0,0",                   # initialise r0 to zero
+                # chr-copy loop starts here:
+                #   for (i = 0; i < n && src[i] != '\0'; i++)
+                #        dest[i] = src[i];
+                # VL (and r1) = MIN(CTR,MAXVL=4)
+                "setvl 1,0,%d,0,1,1" % maxvl,
+                # load VL bytes (update r10 addr)
+                "sv.lbzu/pi *16, 1(10)",         # should be /lf here as well
+                "sv.cmpi/ff=eq/vli *0,1,*16,0",  # cmp against zero, truncate VL
+                # store VL bytes (update r12 addr)
+                "sv.stbu/pi *16, 1(12)",
+                "sv.bc/all 0, *2, -0x1c",       # test CTR, stop if cmpi failed
+                # zeroing loop starts here:
+                #   for ( ; i < n; i++)
+                #       dest[i] = '\0';
+                # VL (and r1) = MIN(CTR,MAXVL=4)
+                "setvl 1,0,%d,0,1,1" % maxvl,
+                # store VL zeros (update r12 addr)
+                "sv.stbu/pi 0, 1(12)",
+                "sv.bc 16, *0, -0xc",           # dec CTR by VL, stop at zero
+            ]
+        )
+        lst = list(lst)
+
+        tst_string = "hello\x00bye\x00"
+        initial_regs = [0] * 32
+        initial_regs[3] = len(tst_string)  # including the zero
+        initial_regs[10] = 16  # load address
+        initial_regs[12] = 40  # store address
+
+        # some memory with identifying garbage in it
+        initial_mem = {16: 0xf0f1_f2f3_f4f5_f6f7,
+                       24: 0x4041_4243_4445_4647,
+                       40: 0x8081_8283_8485_8687,
+                       48: 0x9091_9293_9495_9697,
+                       }
+
+        for i, c in enumerate(tst_string):
+            write_byte(initial_mem, 16+i, ord(c))
+
+        # now get the expected results: copy the string to the other address,
+        # but terminate at first zero (strncpy, duh)
+        expected_mem = deepcopy(initial_mem)
+        copyzeros = False
+        strlen = 0
+        for i, c in enumerate(tst_string):
+            c = ord(c)
+            if not copyzeros:
+                write_byte(expected_mem, 40+i, c)
+                strlen = i+1
+            else:
+                write_byte(expected_mem, 40+i, 0)
+            if c == 0:
+                copyzeros = True
+
+        with Program(lst, bigendian=False) as program:
+            sim = self.run_tst_program(program, initial_mem=initial_mem,
+                                       initial_regs=initial_regs)
+            mem = sim.mem.dump(printout=True, asciidump=True)
+            #print (mem)
+            # contents of memory expected at:
+            #    element 0:   r1=0x10, D=24, => EA = 0x10+24*0 = 16 (0x10)
+            #    element 1:   r1=0x10, D=24, => EA = 0x10+24*1 = 40 (0x28)
+            # therefore, at address 0x10 ==> 0x1234
+            # therefore, at address 0x28 ==> 0x1235
+            for (k, val) in expected_mem.items():
+                print("mem, val", k, hex(val))
+            self.assertEqual(mem, list(expected_mem.items()))
+            print(sim.gpr(1))
+            # reg 10 (the LD EA) is expected to be nearest
+            # 16 + strlen, rounded up
+            rounded = ((strlen+maxvl-1) // maxvl) * maxvl
+            self.assertEqual(sim.gpr(10), SelectableInt(16+rounded, 64))
+            # whereas reg 10 (the ST EA) is expected to be 40+strlen
+            self.assertEqual(sim.gpr(12), SelectableInt(
+                40+len(tst_string), 64))
+
+    def run_tst_program(self, prog, initial_regs=None,
+                        svstate=None, initial_fprs=None,
+                        initial_mem=None):
+        if initial_regs is None:
+            initial_regs = [0] * 32
+        if initial_fprs is None:
+            initial_fprs = [0] * 32
+        simulator = run_tst(prog, initial_regs, svstate=svstate,
+                            initial_fprs=initial_fprs,
+                            mem=initial_mem)
+        print("GPRs")
+        simulator.gpr.dump()
+        print("FPRs")
+        simulator.fpr.dump()
+        return simulator
+
+
+if __name__ == "__main__":
+    unittest.main()