add FPADD, FPSUB, FPMUL, FPDIV quick hacked functions
[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 FRT = SelectableInt(0, 64)
158 z1 = SelectableInt(0, 1)
159 z29 = SelectableInt(0, 29)
160 # Normalized Operand
161 if WORD[1:9] > 0 and WORD[1:9] < 255:
162 FRT[0:2] = WORD[0:2]
163 FRT[2] = ~WORD[1]
164 FRT[3] = ~WORD[1]
165 FRT[4] = ~WORD[1]
166 FRT[5:64] = selectconcat(WORD[2:32], z29)
167
168 # Denormalized Operand
169 if WORD[1:9] == 0 and WORD[9:32] != 0:
170 sign = WORD[0]
171 exp = -126
172 frac = selectconcat(z1, WORD[9:32], z29)
173 # normalize the operand
174 while frac[0] == 0:
175 frac[0:53] = selectconcat(frac[1:53], z1)
176 exp = exp - 1
177 FRT[0] = sign
178 FRT[1:12] = exp + 1023
179 FRT[12:64] = frac[1:53]
180
181 # Zero / Infinity / NaN
182 if WORD[1:9] == 255 or WORD[1:32] == 0:
183 FRT[0:2] = WORD[0:2]
184 FRT[2] = WORD[1]
185 FRT[3] = WORD[1]
186 FRT[4] = WORD[1]
187 FRT[5:64] = selectconcat(WORD[2:32], z29)
188
189 return FRT
190
191
192 def SINGLE(FRS):
193 """convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
194 """
195 # result - WORD - start off all zeros
196 WORD = SelectableInt(0, 32)
197
198 #No Denormalization Required (includes Zero / Infinity / NaN)
199 if FRS[1:12] > 896 or FRS[1:64] == 0:
200 WORD[0:2] = FRS[0:2]
201 WORD[2:32] = FRS[5:35]
202
203 #Denormalization Required
204 if FRS[1:12] >= 874 and FRS[1:12] <= 896:
205 sign = FRS[0]
206 exp = FRS[1:12] - 1023
207 frac = selectconcat(SelectableInt(1, 1), FRS[12:64])
208 # denormalize operand
209 while exp < -126:
210 frac[0:53] = selectconcat(SelectableInt(0, 1), frac[0:52])
211 exp = exp + 1
212 WORD[0] = sign
213 WORD[1:9] = SelectableInt(0, 8)
214 WORD[9:32] = frac[1:24]
215 #else WORD = undefined # return zeros
216
217 return WORD
218
219 def fp64toselectable(frt):
220 """convert FP number to 64 bit SelectableInt
221 """
222 b = struct.pack(">d", frt)
223 val = int.from_bytes(b, byteorder='big', signed=False)
224 return SelectableInt(val, 64)
225
226
227 def FPADD(FRA, FRB):
228 result = float(FRA) + float(FRB)
229 cvt = fp64toselectable(result)
230 print ("FPADD", FRA, FRB, result, cvt)
231
232
233 def FPSUB(FRA, FRB):
234 result = float(FRA) - float(FRB)
235 cvt = fp64toselectable(result)
236 print ("FPSUB", FRA, FRB, result, cvt)
237
238
239 def FPMUL(FRA, FRB):
240 result = float(FRA) * float(FRB)
241 cvt = fp64toselectable(result)
242 print ("FPMUL", FRA, FRB, result, cvt)
243
244
245 def FPDIV(FRA, FRB):
246 result = float(FRA) / float(FRB)
247 cvt = fp64toselectable(result)
248 print ("FPMUL", FRA, FRB, result, cvt)
249
250
251 # For these tests I tried to find power instructions that would let me
252 # isolate each of these helper operations. So for instance, when I was
253 # testing the MASK() function, I chose rlwinm and rldicl because if I
254 # set the shift equal to 0 and passed in a value of all ones, the
255 # result I got would be exactly the same as the output of MASK()
256
257
258 class HelperTests(unittest.TestCase):
259 def test_MASK(self):
260 # Verified using rlwinm, rldicl, rldicr in qemu
261 # li 1, -1
262 # rlwinm reg, 1, 0, 5, 15
263 self.assertHex(MASK(5+32, 15+32), 0x7ff0000)
264 # rlwinm reg, 1, 0, 15, 5
265 self.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
266 self.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
267 # rldicl reg, 1, 0, 37
268 self.assertHex(MASK(37, 63), 0x7ffffff)
269 self.assertHex(MASK(10, 63), 0x3fffffffffffff)
270 self.assertHex(MASK(58, 63), 0x3f)
271 # rldicr reg, 1, 0, 37
272 self.assertHex(MASK(0, 37), 0xfffffffffc000000)
273 self.assertHex(MASK(0, 10), 0xffe0000000000000)
274 self.assertHex(MASK(0, 58), 0xffffffffffffffe0)
275
276 # li 2, 5
277 # slw 1, 1, 2
278 self.assertHex(MASK(32, 63-5), 0xffffffe0)
279
280 self.assertHex(MASK(32, 33), 0xc0000000)
281 self.assertHex(MASK(32, 32), 0x80000000)
282 self.assertHex(MASK(33, 33), 0x40000000)
283
284 def test_ROTL64(self):
285 # r1 = 0xdeadbeef12345678
286 value = 0xdeadbeef12345678
287
288 # rldicl reg, 1, 10, 0
289 self.assertHex(ROTL64(value, 10), 0xb6fbbc48d159e37a)
290 # rldicl reg, 1, 35, 0
291 self.assertHex(ROTL64(value, 35), 0x91a2b3c6f56df778)
292 self.assertHex(ROTL64(value, 58), 0xe37ab6fbbc48d159)
293 self.assertHex(ROTL64(value, 22), 0xbbc48d159e37ab6f)
294
295 def test_ROTL32(self):
296 # r1 = 0xdeadbeef
297 value = 0xdeadbeef
298
299 # rlwinm reg, 1, 10, 0, 31
300 self.assertHex(ROTL32(value, 10), 0xb6fbbf7a)
301 # rlwinm reg, 1, 17, 0, 31
302 self.assertHex(ROTL32(value, 17), 0x7ddfbd5b)
303 self.assertHex(ROTL32(value, 25), 0xdfbd5b7d)
304 self.assertHex(ROTL32(value, 30), 0xf7ab6fbb)
305
306 def test_EXTS64(self):
307 value_a = SelectableInt(0xdeadbeef, 32) # r1
308 value_b = SelectableInt(0x73123456, 32) # r2
309 value_c = SelectableInt(0x80000000, 32) # r3
310
311 # extswsli reg, 1, 0
312 self.assertHex(EXTS64(value_a), 0xffffffffdeadbeef)
313 # extswsli reg, 2, 0
314 self.assertHex(EXTS64(value_b), SelectableInt(value_b.value, 64))
315 # extswsli reg, 3, 0
316 self.assertHex(EXTS64(value_c), 0xffffffff80000000)
317
318 def test_FPADD(self):
319 value_a = SelectableInt(0x4014000000000000, 64) # 5.0
320 value_b = SelectableInt(0x403B4CCCCCCCCCCD, 64) # 27.3
321 result = FPADD(value_a, value_b)
322 self.assertHex(0x4040266666666666, result)
323
324 def assertHex(self, a, b):
325 a_val = a
326 if isinstance(a, SelectableInt):
327 a_val = a.value
328 b_val = b
329 if isinstance(b, SelectableInt):
330 b_val = b.value
331 msg = "{:x} != {:x}".format(a_val, b_val)
332 return self.assertEqual(a, b, msg)
333
334
335 if __name__ == '__main__':
336 print(SelectableInt.__bases__)
337 unittest.main()