format code removing unused imports
[openpower-isa.git] / src / openpower / decoder / isa / test_caller_bcd_full.py
1 import unittest
2 from hashlib import sha256
3 from textwrap import dedent
4
5 from nmutil.formaltest import FHDLTestCase
6 from openpower.decoder.isa.test_runner import run_tst
7 from openpower.decoder.power_decoder import create_pdecode
8 from openpower.decoder.power_decoder2 import PowerDecode2
9 from openpower.decoder.selectable_int import SelectableInt
10 from openpower.simulator.program import Program
11
12
13 def mock_pia():
14 class InstructionInput:
15 def __init__(self, ra=None, rb=None, rc=None, immediate=None, carry=None, overflow=None):
16 self.ra = ra
17 self.rb = rb
18 self.rc = rc
19 self.immediate = immediate
20 self.carry = carry
21 self.overflow = overflow
22
23 class InstructionOutput:
24 def __init__(self, rt=None, overflow=None, carry=None, cr0=None, cr1=None, cr2=None,
25 cr3=None, cr4=None, cr5=None, cr6=None, cr7=None):
26 self.rt = rt
27 self.overflow = overflow
28 self.carry = carry
29 self.cr0 = cr0
30 self.cr1 = cr1
31 self.cr2 = cr2
32 self.cr3 = cr3
33 self.cr4 = cr4
34 self.cr5 = cr5
35 self.cr6 = cr6
36 self.cr7 = cr7
37
38 def pack_bits(*bits):
39 retval = 0
40 for bit in bits:
41 retval <<= 1
42 if bit:
43 retval |= 1
44 return retval
45
46 def unpack_bits(bits, count):
47 return tuple(((bits >> i) & 1) != 0
48 for i in reversed(range(count)))
49
50 def dpd_to_bcd(dpd):
51 # expressions taken from PowerISA v2.07B section B.2 (page 697 (728))
52 p, q, r, s, t, u, v, w, x, y = unpack_bits(dpd, 10)
53 a = (not s and v and w) or (t and v and w and s) or (v and w and not x)
54 b = (p and s and x and not t) or (p and not w) or (p and not v)
55 c = (q and s and x and not t) or (q and not w) or (q and not v)
56 d = r
57 e = (v and not w and x) or (
58 s and v and w and x) or (not t and v and x and w)
59 f = (p and t and v and w and x and not s) or (
60 s and not x and v) or (s and not v)
61 g = (q and t and w and v and x and not s) or (
62 t and not x and v) or (t and not v)
63 h = u
64 i = (t and v and w and x) or (
65 s and v and w and x) or (v and not w and not x)
66 j = (p and not s and not t and w and v) or (s and v and not w and x) or (
67 p and w and not x and v) or (w and not v)
68 k = (q and not s and not t and v and w) or (t and v and not w and x) or (
69 q and v and w and not x) or (x and not v)
70 m = y
71 return pack_bits(a, b, c, d, e, f, g, h, i, j, k, m)
72
73 def bcd_to_dpd(bcd):
74 # expressions taken from PowerISA v2.07B section B.1 (page 697 (728))
75 a, b, c, d, e, f, g, h, i, j, k, m = unpack_bits(bcd, 12)
76 p = (f and a and i and not e) or (j and a and not i) or (b and not a)
77 q = (g and a and i and not e) or (k and a and not i) or (c and not a)
78 r = d
79 s = (j and not a and e and not i) or (f and not i and not e) or (
80 f and not a and not e) or (e and i)
81 t = (k and not a and e and not i) or (g and not i and not e) or (
82 g and not a and not e) or (a and i)
83 u = h
84 v = a or e or i
85 w = (not e and j and not i) or (e and i) or a
86 x = (not a and k and not i) or (a and i) or e
87 y = m
88 return pack_bits(p, q, r, s, t, u, v, w, x, y)
89
90 class pia:
91 @staticmethod
92 def cdtbcd(inputs):
93 ra = inputs.ra & ((1 << 64) - 1)
94 rt = 0
95 rt |= dpd_to_bcd(ra & 0x3FF)
96 rt |= dpd_to_bcd((ra >> 10) & 0x3FF) << 12
97 rt |= dpd_to_bcd((ra >> 32) & 0x3FF) << 32
98 rt |= dpd_to_bcd((ra >> 42) & 0x3FF) << 44
99 return InstructionOutput(rt=rt)
100
101 @staticmethod
102 def cbcdtd(inputs):
103 ra = inputs.ra & ((1 << 64) - 1)
104 rt = 0
105 rt |= bcd_to_dpd(ra & 0xFFF)
106 rt |= bcd_to_dpd((ra >> 12) & 0xFFF) << 10
107 rt |= bcd_to_dpd((ra >> 32) & 0xFFF) << 32
108 rt |= bcd_to_dpd((ra >> 44) & 0xFFF) << 42
109 return InstructionOutput(rt=rt)
110
111 @staticmethod
112 def addg6s(inputs):
113 ra = inputs.ra & ((1 << 64) - 1)
114 rb = inputs.rb & ((1 << 64) - 1)
115 sum = ra + rb
116 need_sixes = ((~sum >> 4) ^ (ra >> 4) ^ (
117 rb >> 4)) & 0x1111_1111_1111_1111
118 rt = 6 * need_sixes
119 return InstructionOutput(rt=rt)
120
121 pia.InstructionInput = InstructionInput
122 pia.InstructionOutput = InstructionOutput
123 return pia
124
125
126 MOCK_PIA = True # until pia is ported to python
127 if MOCK_PIA:
128 pia = mock_pia()
129 else:
130 import power_instruction_analyzer as pia
131
132
133 class BCDFullTestCase(FHDLTestCase):
134 """test full arbitrary bit patterns, including invalid BCD (not
135 supported by above reference code), against power-instruction-analyzer"""
136
137 TEST_INDEX_COUNT = 8
138 pdecode2 = None
139
140 def __init__(self, *args, **kwargs):
141 super().__init__(*args, **kwargs)
142 if BCDFullTestCase.pdecode2 is None:
143 pdecode = create_pdecode()
144 BCDFullTestCase.pdecode2 = PowerDecode2(pdecode)
145
146 def hash(self, v):
147 return int.from_bytes(
148 sha256(bytes(str(v), encoding='ascii')).digest(),
149 byteorder='little'
150 )
151
152 def addg6s_tst_cases(self):
153 mask = (1 << 64) - 1
154 for i in range(1024):
155 v = self.hash(i)
156 yield (v & mask, (v >> 64) & mask)
157
158 def bcd_dpd_tst_cases(self):
159 mask = (1 << 64) - 1
160 limit = 1 << 12
161 for i in range(limit):
162 v = self.hash(i)
163 v &= mask # mask to 64-bits
164 # replace lower bits with `i` to ensure we cover all patterns
165 v &= ~(limit - 1)
166 v |= i
167 yield (v,)
168
169 def run_cases(self, test_index, test_cases, instr, arg_in_count):
170 pia_func = getattr(pia, instr.replace('.', '_'))
171 lst = []
172 for i in range(0, 32, arg_in_count):
173 input_args = ', '.join(str(i + j)
174 for j in range(arg_in_count))
175 lst.append(f"{instr} {i}, {input_args}")
176 with Program(lst, bigendian=False) as program:
177 pass
178 test_cases = list(test_cases)
179 outer_start_index = test_index \
180 * len(test_cases) // self.TEST_INDEX_COUNT
181 outer_end_index = (test_index + 1) \
182 * len(test_cases) // self.TEST_INDEX_COUNT
183 for outer_index in range(outer_start_index, outer_end_index, len(lst)):
184 inner_start_index = outer_index
185 inner_end_index = min(outer_end_index,
186 inner_start_index + len(lst))
187 inner_range = range(inner_start_index, inner_end_index)
188 initial_regs = [0 for i in range(32)]
189 expected_outputs = initial_regs.copy()
190 reg_num = 0
191 for i in inner_range:
192 for j in range(arg_in_count):
193 v = test_cases[i][j]
194 initial_regs[reg_num + j] = v
195 expected_outputs[reg_num + j] = v
196 inputs = pia.InstructionInput(ra=test_cases[i][0])
197 if 1 < arg_in_count:
198 inputs.rb = test_cases[i][1]
199 outputs = pia_func(inputs)
200 expected_outputs[reg_num] = outputs.rt
201 reg_num += arg_in_count
202 with self.subTest(inner_range=inner_range):
203 sim = run_tst(program, initial_regs, pdecode2=self.pdecode2)
204 for reg_num in range(32):
205 with self.subTest(reg_num=reg_num):
206 self.assertEqual(sim.gpr(reg_num),
207 SelectableInt(expected_outputs[reg_num], 64))
208 pass
209
210 def tst_addg6s(self, test_index):
211 self.run_cases(test_index, self.addg6s_tst_cases(), 'addg6s', 2)
212
213 def tst_cdtbcd(self, test_index):
214 self.run_cases(test_index, self.bcd_dpd_tst_cases(), 'cdtbcd', 1)
215
216 def tst_cbcdtd(self, test_index):
217 self.run_cases(test_index, self.bcd_dpd_tst_cases(), 'cbcdtd', 1)
218
219
220 for i in range(BCDFullTestCase.TEST_INDEX_COUNT):
221 for j in 'addg6s', 'cdtbcd', 'cbcdtd':
222 exec(dedent(f"""
223 def tst_{j}_{i}(self):
224 self.tst_{j}({i})
225 BCDFullTestCase.test_{j}_{i} = tst_{j}_{i}
226 """))
227
228 if __name__ == "__main__":
229 unittest.main()