bug 676: add /mr to sv.minmax.
[openpower-isa.git] / src / openpower / decoder / isa / test_caller_svp64_maxloc.py
1 """Implementation of FORTRAN MAXLOC SVP64
2 Copyright (C) 2022,2023 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 Licensed under the LGPLv3+
4 Funded by NLnet NGI-ASSURE under EU grant agreement No 957073.
5 * https://nlnet.nl/project/Libre-SOC-OpenPOWER-ISA
6 * https://bugs.libre-soc.org/show_bug.cgi?id=676
7 * https://libre-soc.org/openpower/sv/cookbook/fortran_maxloc/
8 """
9
10 import unittest
11 import random
12 from copy import deepcopy
13
14 from nmutil.formaltest import FHDLTestCase
15 from openpower.decoder.isa.caller import SVP64State
16 from openpower.decoder.isa.test_caller import run_tst
17 from openpower.decoder.selectable_int import SelectableInt
18 from openpower.simulator.program import Program
19 from openpower.insndb.asm import SVP64Asm
20 from openpower.util import log
21 from openpower.decoder.isa.maxloc import m2
22
23
24
25 def cmpd(x, y):
26 class CRfield:
27 def __repr__(self):
28 return "<lt %d gt %d eq %d>" % (self.lt, self.gt, self.eq)
29 def __int__(self):
30 return (CRf.lt<<3) | (CRf.gt<<2) | (CRf.eq<<1)
31 CRf = CRfield()
32 CRf.lt = x < y
33 CRf.gt = x > y
34 CRf.eq = x == y
35 return CRf
36
37
38 # example sv.minmax/ff=lt 0, 1, *10, 5
39 # see https://bugs.libre-soc.org/show_bug.cgi?id=1183#c3
40 def sv_maxu(gpr, vl, ra, rb, rt):
41 CR0, i = None, 0
42 while i < vl:
43 CR0 = cmpd(gpr[ra+i], gpr[rb])
44 log("sv_maxss test", i, gpr[ra + i], gpr[rb], CR0, int(CR0))
45 gpr[rt] = gpr[ra+i] if CR0.lt else gpr[rb]
46 if not CR0.gt:
47 break
48 i += 1
49 return i, CR0 # new VL
50
51
52 class DDFFirstTestCase(FHDLTestCase):
53
54 def _check_regs(self, sim, expected):
55 for i in range(32):
56 self.assertEqual(sim.gpr(i), SelectableInt(expected[i], 64))
57
58 def test_sv_maxloc_1(self):
59 self.sv_maxloc([1,3,3,3])
60
61 def test_sv_maxloc_2(self):
62 self.sv_maxloc([3,4,1,5])
63
64 def test_sv_maxloc_3(self):
65 self.sv_maxloc([2,9,8,0])
66
67 def test_sv_maxloc_4(self):
68 self.sv_maxloc([2,1,3,0])
69
70 def test_sv_maxloc_5(self):
71 self.sv_maxloc([0,0,0,0])
72
73 def test_sv_maxloc_6(self):
74 self.sv_maxloc([0,9,9,3])
75
76 def test_sv_maxloc_7(self):
77 self.sv_maxloc([9,0,10,11])
78
79 def test_sv_maxloc_random(self):
80 random.seed(1) # set the same seed (consistent test)
81 for i in range(50):
82 array = []
83 for j in range(4):
84 array.append(random.randint(0, 20))
85 with self.subTest(i=i):
86 self.sv_maxloc(array)
87
88 def sv_maxloc(self, ra):
89 """
90 m, nm, i, n = 0, 0, 0, len(a)
91 while (i<n):
92 while (i<n and a[i]<=m) : i += 1
93 while (i<n and a[i] > m): m, nm, i = a[i], i, i+1
94 return nm
95 """
96
97 # note that m (above) is r4. sv.cmp can be used in the first
98 # while loop because m (r4) does not change. sv.minmax. has
99 # to be used in the key while loop because r4 is sequentially
100 # replaced (mapreduce mode) each time. also note that i is
101 # represented as a bitmask (CR bits 16,20,24,28)
102
103 lst = SVP64Asm([
104 # while (i<n)
105 "setvl 2,0,4,0,1,1", # set MVL=4, VL=MIN(MVL,CTR)
106 # while (i<n and a[i]<=m) : i += 1
107 "sv.cmp/ff=gt/m=ge *0,0,*10,4", # truncates VL to min
108 "sv.creqv *16,*16,*16", # set mask on already-tested
109 "setvl 2,0,4,0,1,1", # set MVL=4, VL=MIN(MVL,CTR)
110 "mtcrf 128, 0", # clear CR0 (in case VL=0?)
111 # while (i<n and a[i]>m):
112 "sv.minmax./ff=le/m=ge/mr 4,*10,4,1", # uses r4 as accumulator
113 "crternlogi 0,1,2,127", # test greater/equal or VL=0
114 "sv.crand *19,*16,0", # clear if CR0.eq=0
115 # nm = i (count masked bits. could use crweirds here TODO)
116 "sv.svstep/mr/m=so 1, 0, 6, 1", # svstep: get vector dststep
117 "sv.creqv *16,*16,*16", # set mask on already-tested
118 "bc 12,0, -0x40" # CR0 lt bit clear, branch back
119 ])
120 lst = list(lst)
121
122 # SVSTATE
123 svstate = SVP64State()
124 vl = len(ra) # VL is length of array ra
125 svstate.vl = vl # VL
126 svstate.maxvl = vl # MAXVL
127 print("SVSTATE", bin(svstate.asint()))
128
129 gprs = [0] * 32
130 gprs[3] = vl # variable n: to go into CTR
131 gprs[4] = 2 # variable m: max current number found
132 for i, ra in enumerate(ra): # vector in ra starts at r10
133 gprs[10+i] = ra
134 log("maxu ddff", i, gprs[10+i])
135
136 cr_res = [0]*8
137 res = deepcopy(gprs)
138
139 #expected_vl, expected_cr = sv_maxu(res, cr_res, vl, 10, 4, 4)
140 #log("sv_maxu", expected_vl, cr_res)
141
142 with Program(lst, bigendian=False) as program:
143 sim = self.run_tst_program(program, initial_regs=gprs,
144 svstate=svstate)
145 for i in range(vl):
146 val = sim.gpr(i).value
147 res.append(val)
148 cr_res.append(0)
149 log("i", i, val)
150
151 for i in range(vl):
152 crf = sim.crl[i].get_range().value
153 log("crf", i, bin(crf))
154
155 # confirm that the results are as expected
156 return
157
158 for i, v in enumerate(cr_res[:vl]):
159 crf = sim.crl[i].get_range().value
160 log("crf", i, res[i], bin(crf), bin(int(v)))
161 self.assertEqual(crf, int(v))
162
163 for i, v in enumerate(res):
164 self.assertEqual(v, res[i])
165
166 #self.assertEqual(sim.svstate.vl, expected_vl)
167 #self.assertEqual(sim.svstate.maxvl, 4)
168 #self.assertEqual(sim.svstate.srcstep, 0)
169 #self.assertEqual(sim.svstate.dststep, 0)
170
171 def run_tst_program(self, prog, initial_regs=None,
172 svstate=None,
173 initial_mem=None,
174 initial_fprs=None):
175 if initial_regs is None:
176 initial_regs = [0] * 32
177 simulator = run_tst(prog, initial_regs, mem=initial_mem,
178 initial_fprs=initial_fprs,
179 svstate=svstate)
180
181 print("GPRs")
182 simulator.gpr.dump()
183 print("FPRs")
184 simulator.fpr.dump()
185
186 return simulator
187
188
189 if __name__ == "__main__":
190 unittest.main()