add comments on trunc_div and trunc_rem
[soc.git] / src / soc / decoder / helpers.py
1 import unittest
2 from soc.decoder.selectable_int import SelectableInt
3
4 """
5 Links:
6 * https://bugs.libre-soc.org/show_bug.cgi?id=324 - add trunc_div and trunc_rem
7 """
8
9 def exts(value, bits):
10 sign = 1 << (bits - 1)
11 return (value & (sign - 1)) - (value & sign)
12
13
14 # this is a POWER ISA 3.0B compatible div function
15 def trunc_div(n, d):
16 f = getattr(n, "trunc_div", None)
17 if f is not None:
18 return f(d)
19 fr = getattr(d, "rtrunc_div", None)
20 if fr is not None:
21 return fr(n)
22 abs_n = abs(n)
23 abs_d = abs(d)
24 abs_q = n // d
25 if (n < 0) == (d < 0):
26 return abs_q
27 return -abs_q
28
29
30 # this is a POWER ISA 3.0B compatible mod / remainder function
31 def trunc_rem(n, d):
32 f = getattr(n, "trunc_rem", None)
33 if f is not None:
34 return f(d)
35 fr = getattr(d, "rtrunc_rem", None)
36 if fr is not None:
37 return fr(n)
38 return n - d * trunc_div(n, d)
39
40
41 def EXTS(value):
42 """ extends sign bit out from current MSB to all 256 bits
43 """
44 assert isinstance(value, SelectableInt)
45 return SelectableInt(exts(value.value, value.bits) & ((1 << 256)-1), 256)
46
47 def EXTS64(value):
48 """ extends sign bit out from current MSB to 64 bits
49 """
50 assert isinstance(value, SelectableInt)
51 return SelectableInt(exts(value.value, value.bits) & ((1 << 64)-1), 64)
52
53
54 # XXX should this explicitly extend from 32 to 64?
55 def EXTZ64(value):
56 if isinstance(value, SelectableInt):
57 value = value.value
58 return SelectableInt(value & ((1<<32)-1), 64)
59
60
61 def rotl(value, bits, wordlen):
62 if isinstance(bits, SelectableInt):
63 bits = bits.value
64 mask = (1 << wordlen) - 1
65 bits = bits & (wordlen - 1)
66 return ((value << bits) | (value >> (wordlen-bits))) & mask
67
68
69 def ROTL64(value, bits):
70 return rotl(value, bits, 64)
71
72
73 def ROTL32(value, bits):
74 if isinstance(value, SelectableInt):
75 value = SelectableInt(value.value, 64)
76 return rotl(value | (value << 32), bits, 64)
77
78
79 def MASK(x, y):
80 if isinstance(x, SelectableInt):
81 x = x.value
82 if isinstance(y, SelectableInt):
83 y = y.value
84 if x < y:
85 x = 64-x
86 y = 63-y
87 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
88 mask_b = ((1 << y) - 1) & ((1 << 64) - 1)
89 elif x == y:
90 return 1 << (63-x)
91 else:
92 x = 64-x
93 y = 63-y
94 mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
95 mask_b = (~((1 << y) - 1)) & ((1 << 64) - 1)
96 return mask_a ^ mask_b
97
98 def ne(a, b):
99 return SelectableInt((a != b), bits=1)
100
101 def eq(a, b):
102 return SelectableInt((a == b), bits=1)
103
104 def gt(a, b):
105 return SelectableInt((a > b), bits=1)
106
107 def ge(a, b):
108 return SelectableInt((a >= b), bits=1)
109
110 def lt(a, b):
111 return SelectableInt((a < b), bits=1)
112
113 def le(a, b):
114 return SelectableInt((a <= b), bits=1)
115
116 def length(a):
117 return len(a)
118
119 # For these tests I tried to find power instructions that would let me
120 # isolate each of these helper operations. So for instance, when I was
121 # testing the MASK() function, I chose rlwinm and rldicl because if I
122 # set the shift equal to 0 and passed in a value of all ones, the
123 # result I got would be exactly the same as the output of MASK()
124
125 class HelperTests(unittest.TestCase):
126 def test_MASK(self):
127 # Verified using rlwinm, rldicl, rldicr in qemu
128 # li 1, -1
129 # rlwinm reg, 1, 0, 5, 15
130 self.assertHex(MASK(5+32, 15+32), 0x7ff0000)
131 # rlwinm reg, 1, 0, 15, 5
132 self.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
133 self.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
134 # rldicl reg, 1, 0, 37
135 self.assertHex(MASK(37, 63), 0x7ffffff)
136 self.assertHex(MASK(10, 63), 0x3fffffffffffff)
137 self.assertHex(MASK(58, 63), 0x3f)
138 # rldicr reg, 1, 0, 37
139 self.assertHex(MASK(0, 37), 0xfffffffffc000000)
140 self.assertHex(MASK(0, 10), 0xffe0000000000000)
141 self.assertHex(MASK(0, 58), 0xffffffffffffffe0)
142
143 # li 2, 5
144 # slw 1, 1, 2
145 self.assertHex(MASK(32, 63-5), 0xffffffe0)
146
147 self.assertHex(MASK(32, 33), 0xc0000000)
148 self.assertHex(MASK(32, 32), 0x80000000)
149 self.assertHex(MASK(33, 33), 0x40000000)
150
151 def test_ROTL64(self):
152 # r1 = 0xdeadbeef12345678
153 value = 0xdeadbeef12345678
154
155 # rldicl reg, 1, 10, 0
156 self.assertHex(ROTL64(value, 10), 0xb6fbbc48d159e37a)
157 # rldicl reg, 1, 35, 0
158 self.assertHex(ROTL64(value, 35), 0x91a2b3c6f56df778)
159 self.assertHex(ROTL64(value, 58), 0xe37ab6fbbc48d159)
160 self.assertHex(ROTL64(value, 22), 0xbbc48d159e37ab6f)
161
162 def test_ROTL32(self):
163 # r1 = 0xdeadbeef
164 value = 0xdeadbeef
165
166 # rlwinm reg, 1, 10, 0, 31
167 self.assertHex(ROTL32(value, 10), 0xb6fbbf7a)
168 # rlwinm reg, 1, 17, 0, 31
169 self.assertHex(ROTL32(value, 17), 0x7ddfbd5b)
170 self.assertHex(ROTL32(value, 25), 0xdfbd5b7d)
171 self.assertHex(ROTL32(value, 30), 0xf7ab6fbb)
172
173 def test_EXTS64(self):
174 value_a = SelectableInt(0xdeadbeef, 32) # r1
175 value_b = SelectableInt(0x73123456, 32) # r2
176 value_c = SelectableInt(0x80000000, 32) # r3
177
178 # extswsli reg, 1, 0
179 self.assertHex(EXTS64(value_a), 0xffffffffdeadbeef)
180 # extswsli reg, 2, 0
181 self.assertHex(EXTS64(value_b), SelectableInt(value_b.value, 64))
182 # extswsli reg, 3, 0
183 self.assertHex(EXTS64(value_c), 0xffffffff80000000)
184
185 def assertHex(self, a, b):
186 a_val = a
187 if isinstance(a, SelectableInt):
188 a_val = a.value
189 b_val = b
190 if isinstance(b, SelectableInt):
191 b_val = b.value
192 msg = "{:x} != {:x}".format(a_val, b_val)
193 return self.assertEqual(a, b, msg)
194
195
196 if __name__ == '__main__':
197 print (SelectableInt.__bases__)
198 unittest.main()