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