f0dc1da32053da43c0836bb05961016b750b1ff4
[openpower-isa.git] / src / openpower / decoder / helpers.py
1 import unittest
2 import struct
3 from openpower.decoder.selectable_int import (SelectableInt, onebit,
4 selectconcat)
5 from nmutil.divmod import trunc_divs, trunc_rems
6 from operator import floordiv, mod
7 from openpower.decoder.selectable_int import selectltu as ltu
8 from openpower.decoder.selectable_int import selectgtu as gtu
9 from openpower.decoder.selectable_int import check_extsign
10
11 trunc_div = floordiv
12 trunc_rem = mod
13 DIVS = trunc_divs
14 MODS = trunc_rems
15
16 """
17 Links:
18 * https://bugs.libre-soc.org/show_bug.cgi?id=324 - add trunc_div and trunc_rem
19 """
20
21
22 def exts(value, bits):
23 sign = 1 << (bits - 1)
24 return (value & (sign - 1)) - (value & sign)
25
26
27 def EXTS(value):
28 """ extends sign bit out from current MSB to all 256 bits
29 """
30 print ("EXTS", value, type(value))
31 assert isinstance(value, SelectableInt)
32 return SelectableInt(exts(value.value, value.bits) & ((1 << 256)-1), 256)
33
34
35 def EXTS64(value):
36 """ extends sign bit out from current MSB to 64 bits
37 """
38 assert isinstance(value, SelectableInt)
39 return SelectableInt(exts(value.value, value.bits) & ((1 << 64)-1), 64)
40
41
42 def EXTS128(value):
43 """ extends sign bit out from current MSB to 128 bits
44 """
45 assert isinstance(value, SelectableInt)
46 return SelectableInt(exts(value.value, value.bits) & ((1 << 128)-1), 128)
47
48
49 # signed version of MUL
50 def MULS(a, b):
51 if isinstance(b, int):
52 b = SelectableInt(b, self.bits)
53 b = check_extsign(a, b)
54 a_s = a.value & (1 << (a.bits-1)) != 0
55 b_s = b.value & (1 << (b.bits-1)) != 0
56 result = abs(a) * abs(b)
57 print("MULS", result, a_s, b_s)
58 if a_s == b_s:
59 return result
60 return -result
61
62
63 # XXX should this explicitly extend from 32 to 64?
64 def EXTZ64(value):
65 if isinstance(value, SelectableInt):
66 value = value.value
67 return SelectableInt(value & ((1 << 32)-1), 64)
68
69
70 def rotl(value, bits, wordlen):
71 if isinstance(bits, SelectableInt):
72 bits = bits.value
73 mask = (1 << wordlen) - 1
74 bits = bits & (wordlen - 1)
75 return ((value << bits) | (value >> (wordlen-bits))) & mask
76
77
78 def ROTL64(value, bits):
79 return rotl(value, bits, 64)
80
81
82 def ROTL32(value, bits):
83 if isinstance(bits, SelectableInt):
84 bits = bits.value
85 if isinstance(value, SelectableInt):
86 value = SelectableInt(value.value, 64)
87 return rotl(value | (value << 32), bits, 64)
88
89 def MASK32(x, y):
90 if isinstance(x, SelectableInt):
91 x = x.value
92 if isinstance(y, SelectableInt):
93 y = y.value
94 return MASK(x+32, y+32)
95
96 def MASK(x, y):
97 if isinstance(x, SelectableInt):
98 x = x.value
99 if isinstance(y, SelectableInt):
100 y = y.value
101 if x < y:
102 x = 64-x
103 y = 63-y
104 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
105 mask_b = ((1 << y) - 1) & ((1 << 64) - 1)
106 elif x == y:
107 return 1 << (63-x)
108 else:
109 x = 64-x
110 y = 63-y
111 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
112 mask_b = (~((1 << y) - 1)) & ((1 << 64) - 1)
113 return mask_a ^ mask_b
114
115
116 def ne(a, b):
117 return onebit(a != b)
118
119
120 def eq(a, b):
121 return onebit(a == b)
122
123
124 def gt(a, b):
125 return onebit(a > b)
126
127
128 def ge(a, b):
129 return onebit(a >= b)
130
131
132 def lt(a, b):
133 return onebit(a < b)
134
135
136 def le(a, b):
137 return onebit(a <= b)
138
139
140 def length(a):
141 return len(a)
142
143
144 def undefined(v):
145 """ function that, for Power spec purposes, returns undefined bits of
146 the same shape as the input bits. however, for purposes of matching
147 POWER9's behavior returns the input bits unchanged. this effectively
148 "marks" (tags) locations in the v3.0B spec that need to be submitted
149 for clarification.
150 """
151 return v
152
153 def DOUBLE(WORD):
154 """convert incoming WORD to double. v3.0B p140 section 4.6.2
155 """
156 # result, FRT, start off all zeros
157 print ("WORD", WORD)
158 FRT = SelectableInt(0, 64)
159 z1 = SelectableInt(0, 1)
160 z29 = SelectableInt(0, 29)
161 e = WORD[1:9]
162 m = WORD[9:32]
163 s = WORD[0]
164 print ("word s e m", s, e, m)
165
166 # Normalized Operand
167 if e.value > 0 and e.value < 255:
168 print ("normalised")
169 FRT[0:2] = WORD[0:2]
170 FRT[2] = ~WORD[1]
171 FRT[3] = ~WORD[1]
172 FRT[4] = ~WORD[1]
173 FRT[5:64] = selectconcat(WORD[2:32], z29)
174
175 # Denormalized Operand
176 if e.value == 0 and m.value != 0:
177 print ("denormalised")
178 sign = WORD[0]
179 exp = -126
180 frac = selectconcat(z1, WORD[9:32], z29)
181 # normalize the operand
182 while frac[0].value == 0:
183 frac[0:53] = selectconcat(frac[1:53], z1)
184 exp = exp - 1
185 FRT[0] = sign
186 FRT[1:12] = exp + 1023
187 FRT[12:64] = frac[1:53]
188
189 # Zero / Infinity / NaN
190 if e.value == 255 or m.value == 0:
191 print ("z/inf/nan")
192 FRT[0:2] = WORD[0:2]
193 FRT[2] = WORD[1]
194 FRT[3] = WORD[1]
195 FRT[4] = WORD[1]
196 FRT[5:64] = selectconcat(WORD[2:32], z29)
197
198 print ("Double s e m", FRT[0].value, FRT[1:12].value-1023,
199 FRT[12:64].value)
200
201 return FRT
202
203
204 def SINGLE(FRS):
205 """convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
206 """
207 # result - WORD - start off all zeros
208 WORD = SelectableInt(0, 32)
209
210 e = FRS[1:12]
211 m = FRS[9:32]
212 s = FRS[0]
213
214 print ("SINGLE", FRS)
215 print ("s e m", s.value, e.value, m.value)
216
217 #No Denormalization Required (includes Zero / Infinity / NaN)
218 if e.value > 896 or FRS[1:64].value == 0:
219 WORD[0:2] = FRS[0:2]
220 WORD[2:32] = FRS[5:35]
221
222 #Denormalization Required
223 if e.value >= 874 and e.value <= 896:
224 sign = FRS[0]
225 exp = e - 1023
226 frac = selectconcat(SelectableInt(1, 1), FRS[12:64])
227 # denormalize operand
228 while exp.value < -126:
229 frac[0:53] = selectconcat(SelectableInt(0, 1), frac[0:52])
230 exp = exp + 1
231 WORD[0] = sign
232 WORD[1:9] = SelectableInt(0, 8)
233 WORD[9:32] = frac[1:24]
234 #else WORD = undefined # return zeros
235
236 print ("WORD", WORD)
237
238 return WORD
239
240 # XXX NOTE: these are very quick hacked functions for utterly basic
241 # FP support
242
243 def fp64toselectable(frt):
244 """convert FP number to 64 bit SelectableInt
245 """
246 b = struct.pack(">d", frt)
247 val = int.from_bytes(b, byteorder='big', signed=False)
248 return SelectableInt(val, 64)
249
250
251 def FPADD32(FRA, FRB):
252 FRA = DOUBLE(SINGLE(FRA))
253 FRB = DOUBLE(SINGLE(FRB))
254 result = float(FRA) + float(FRB)
255 cvt = fp64toselectable(result)
256 cvt = DOUBLE(SINGLE(cvt))
257 print ("FPADD32", FRA, FRB, result, cvt)
258 return cvt
259
260
261 def FPSUB32(FRA, FRB):
262 FRA = DOUBLE(SINGLE(FRA))
263 FRB = DOUBLE(SINGLE(FRB))
264 result = float(FRA) - float(FRB)
265 cvt = fp64toselectable(result)
266 cvt = DOUBLE(SINGLE(cvt))
267 print ("FPSUB32", FRA, FRB, result, cvt)
268 return cvt
269
270
271 def FPMUL32(FRA, FRB):
272 FRA = DOUBLE(SINGLE(FRA))
273 FRB = DOUBLE(SINGLE(FRB))
274 result = float(FRA) * float(FRB)
275 cvt = fp64toselectable(result)
276 cvt = DOUBLE(SINGLE(cvt))
277 print ("FPMUL32", FRA, FRB, result, cvt)
278 return cvt
279
280
281 def FPDIV32(FRA, FRB):
282 FRA = DOUBLE(SINGLE(FRA))
283 FRB = DOUBLE(SINGLE(FRB))
284 result = float(FRA) / float(FRB)
285 cvt = fp64toselectable(result)
286 cvt = DOUBLE(SINGLE(cvt))
287 print ("FPDIV32", FRA, FRB, result, cvt)
288 return cvt
289
290
291 def FPADD64(FRA, FRB):
292 result = float(FRA) + float(FRB)
293 cvt = fp64toselectable(result)
294 print ("FPADD64", FRA, FRB, result, cvt)
295
296
297 def FPSUB64(FRA, FRB):
298 result = float(FRA) - float(FRB)
299 cvt = fp64toselectable(result)
300 print ("FPSUB64", FRA, FRB, result, cvt)
301
302
303 def FPMUL64(FRA, FRB):
304 result = float(FRA) * float(FRB)
305 cvt = fp64toselectable(result)
306 print ("FPMUL64", FRA, FRB, result, cvt)
307
308
309 def FPDIV64(FRA, FRB):
310 result = float(FRA) / float(FRB)
311 cvt = fp64toselectable(result)
312 print ("FPDIV64", FRA, FRB, result, cvt)
313
314
315 # For these tests I tried to find power instructions that would let me
316 # isolate each of these helper operations. So for instance, when I was
317 # testing the MASK() function, I chose rlwinm and rldicl because if I
318 # set the shift equal to 0 and passed in a value of all ones, the
319 # result I got would be exactly the same as the output of MASK()
320
321
322 class HelperTests(unittest.TestCase):
323 def test_MASK(self):
324 # Verified using rlwinm, rldicl, rldicr in qemu
325 # li 1, -1
326 # rlwinm reg, 1, 0, 5, 15
327 self.assertHex(MASK(5+32, 15+32), 0x7ff0000)
328 # rlwinm reg, 1, 0, 15, 5
329 self.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
330 self.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
331 # rldicl reg, 1, 0, 37
332 self.assertHex(MASK(37, 63), 0x7ffffff)
333 self.assertHex(MASK(10, 63), 0x3fffffffffffff)
334 self.assertHex(MASK(58, 63), 0x3f)
335 # rldicr reg, 1, 0, 37
336 self.assertHex(MASK(0, 37), 0xfffffffffc000000)
337 self.assertHex(MASK(0, 10), 0xffe0000000000000)
338 self.assertHex(MASK(0, 58), 0xffffffffffffffe0)
339
340 # li 2, 5
341 # slw 1, 1, 2
342 self.assertHex(MASK(32, 63-5), 0xffffffe0)
343
344 self.assertHex(MASK(32, 33), 0xc0000000)
345 self.assertHex(MASK(32, 32), 0x80000000)
346 self.assertHex(MASK(33, 33), 0x40000000)
347
348 def test_ROTL64(self):
349 # r1 = 0xdeadbeef12345678
350 value = 0xdeadbeef12345678
351
352 # rldicl reg, 1, 10, 0
353 self.assertHex(ROTL64(value, 10), 0xb6fbbc48d159e37a)
354 # rldicl reg, 1, 35, 0
355 self.assertHex(ROTL64(value, 35), 0x91a2b3c6f56df778)
356 self.assertHex(ROTL64(value, 58), 0xe37ab6fbbc48d159)
357 self.assertHex(ROTL64(value, 22), 0xbbc48d159e37ab6f)
358
359 def test_ROTL32(self):
360 # r1 = 0xdeadbeef
361 value = 0xdeadbeef
362
363 # rlwinm reg, 1, 10, 0, 31
364 self.assertHex(ROTL32(value, 10), 0xb6fbbf7a)
365 # rlwinm reg, 1, 17, 0, 31
366 self.assertHex(ROTL32(value, 17), 0x7ddfbd5b)
367 self.assertHex(ROTL32(value, 25), 0xdfbd5b7d)
368 self.assertHex(ROTL32(value, 30), 0xf7ab6fbb)
369
370 def test_EXTS64(self):
371 value_a = SelectableInt(0xdeadbeef, 32) # r1
372 value_b = SelectableInt(0x73123456, 32) # r2
373 value_c = SelectableInt(0x80000000, 32) # r3
374
375 # extswsli reg, 1, 0
376 self.assertHex(EXTS64(value_a), 0xffffffffdeadbeef)
377 # extswsli reg, 2, 0
378 self.assertHex(EXTS64(value_b), SelectableInt(value_b.value, 64))
379 # extswsli reg, 3, 0
380 self.assertHex(EXTS64(value_c), 0xffffffff80000000)
381
382 def test_FPADD32(self):
383 value_a = SelectableInt(0x4014000000000000, 64) # 5.0
384 value_b = SelectableInt(0x403B4CCCCCCCCCCD, 64) # 27.3
385 result = FPADD32(value_a, value_b)
386 self.assertHex(0x4040266666666666, result)
387
388 def assertHex(self, a, b):
389 a_val = a
390 if isinstance(a, SelectableInt):
391 a_val = a.value
392 b_val = b
393 if isinstance(b, SelectableInt):
394 b_val = b.value
395 msg = "{:x} != {:x}".format(a_val, b_val)
396 return self.assertEqual(a, b, msg)
397
398
399 if __name__ == '__main__':
400 print(SelectableInt.__bases__)
401 unittest.main()