VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-gen.cpp@ 105845

Last change on this file since 105845 was 104015, checked in by vboxsync, 8 months ago

ValKit/bs3-cpu-instr-2: update docs on odd rol/ror behaviour. bugref:10376

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.6 KB
Line 
1/* $Id: bs3-cpu-instr-2-gen.cpp 104015 2024-03-23 02:04:08Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-instr-2, Test Data Generator.
4 */
5
6/*
7 * Copyright (C) 2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/asm-amd64-x86.h>
44#include <iprt/initterm.h>
45#include <iprt/message.h>
46#include <iprt/rand.h>
47#include <iprt/stream.h>
48#include <iprt/x86.h>
49#include <VBox/disopcode-x86-amd64.h>
50#include "bs3-cpu-instr-2.h"
51
52
53/*********************************************************************************************************************************
54* External Functions *
55*********************************************************************************************************************************/
56#define PROTOTYPE_BINARY(a_Ins) \
57 DECLASM(uint32_t) RT_CONCAT(GenU8_,a_Ins)( uint8_t, uint8_t, uint32_t, uint8_t *); \
58 DECLASM(uint32_t) RT_CONCAT(GenU16_,a_Ins)(uint16_t, uint16_t, uint32_t, uint16_t *); \
59 DECLASM(uint32_t) RT_CONCAT(GenU32_,a_Ins)(uint32_t, uint32_t, uint32_t, uint32_t *); \
60 DECLASM(uint32_t) RT_CONCAT(GenU64_,a_Ins)(uint64_t, uint64_t, uint32_t, uint64_t *)
61
62PROTOTYPE_BINARY(and);
63PROTOTYPE_BINARY(or);
64PROTOTYPE_BINARY(xor);
65PROTOTYPE_BINARY(test);
66
67PROTOTYPE_BINARY(add);
68PROTOTYPE_BINARY(adc);
69PROTOTYPE_BINARY(sub);
70PROTOTYPE_BINARY(sbb);
71PROTOTYPE_BINARY(cmp);
72
73PROTOTYPE_BINARY(bt);
74PROTOTYPE_BINARY(btc);
75PROTOTYPE_BINARY(btr);
76PROTOTYPE_BINARY(bts);
77
78
79#define PROTOTYPE_SHIFT(a_Ins) \
80 DECLASM(uint32_t) RT_CONCAT(GenU8_,a_Ins)( uint8_t, uint8_t, uint32_t, uint8_t *); \
81 DECLASM(uint32_t) RT_CONCAT(GenU16_,a_Ins)(uint16_t, uint8_t, uint32_t, uint16_t *); \
82 DECLASM(uint32_t) RT_CONCAT(GenU32_,a_Ins)(uint32_t, uint8_t, uint32_t, uint32_t *); \
83 DECLASM(uint32_t) RT_CONCAT(GenU64_,a_Ins)(uint64_t, uint8_t, uint32_t, uint64_t *); \
84 DECLASM(uint32_t) RT_CONCAT3(GenU8_,a_Ins,_Ib)( uint8_t, uint8_t, uint32_t, uint8_t *); \
85 DECLASM(uint32_t) RT_CONCAT3(GenU16_,a_Ins,_Ib)(uint16_t, uint8_t, uint32_t, uint16_t *); \
86 DECLASM(uint32_t) RT_CONCAT3(GenU32_,a_Ins,_Ib)(uint32_t, uint8_t, uint32_t, uint32_t *); \
87 DECLASM(uint32_t) RT_CONCAT3(GenU64_,a_Ins,_Ib)(uint64_t, uint8_t, uint32_t, uint64_t *)
88
89PROTOTYPE_SHIFT(shl);
90PROTOTYPE_SHIFT(shr);
91PROTOTYPE_SHIFT(sar);
92PROTOTYPE_SHIFT(rol);
93PROTOTYPE_SHIFT(ror);
94PROTOTYPE_SHIFT(rcl);
95PROTOTYPE_SHIFT(rcr);
96
97
98static uint32_t RandEflStatus(void)
99{
100 return RTRandU32Ex(0, X86_EFL_STATUS_BITS) & X86_EFL_STATUS_BITS;
101}
102
103
104static uint8_t RandU8Shift(unsigned i, unsigned cTests, uint32_t *puTracker, unsigned cBits)
105{
106 uint8_t cShift = (uint8_t)RTRandU32Ex(0, 0xff);
107 if ((cShift % 11) != 0)
108 {
109 if ((cShift % 3) == 0)
110 cShift &= (cBits * 2) - 1;
111 else
112 cShift &= cBits - 1;
113 }
114
115 /* Make sure we've got the following counts: 0, 1, cBits, cBits + 1.
116 Note! Missing shift count 1 will cause the 'shl reg, 1' tests to spin forever. */
117 if (cShift == 0)
118 *puTracker |= RT_BIT_32(0);
119 else if (cShift == 1)
120 *puTracker |= RT_BIT_32(1);
121 else if (cShift == cBits)
122 *puTracker |= RT_BIT_32(2);
123 else if (cShift == cBits + 1)
124 *puTracker |= RT_BIT_32(3);
125 else if (*puTracker != 15 && i > cTests / 2)
126 {
127 if (!(*puTracker & RT_BIT_32(0)))
128 {
129 *puTracker |= RT_BIT_32(0);
130 cShift = 0;
131 }
132 else if (!(*puTracker & RT_BIT_32(1)))
133 {
134 *puTracker |= RT_BIT_32(1);
135 cShift = 1;
136 }
137 else if (!(*puTracker & RT_BIT_32(2)))
138 {
139 *puTracker |= RT_BIT_32(2);
140 cShift = cBits;
141 }
142 else if (!(*puTracker & RT_BIT_32(3)))
143 {
144 *puTracker |= RT_BIT_32(2);
145 cShift = cBits + 1;
146 }
147 else
148 RT_BREAKPOINT();
149 }
150
151 return cShift;
152}
153
154
155static uint8_t RandU8(unsigned i, unsigned iOp, unsigned iOuter = 0, enum OPCODESX86 enmOp = OP_INVALID)
156{
157 RT_NOREF(iOuter, enmOp);
158 if (i == 0)
159 return 0;
160 if (i == 1)
161 return UINT8_MAX;
162 if (i == 2)
163 return iOp == 1 ? 0 : UINT8_MAX;
164 return (uint8_t)RTRandU32Ex(0, UINT8_MAX);
165}
166
167
168static uint16_t RandU16(unsigned i, unsigned iOp, unsigned iOuter, enum OPCODESX86 enmOp)
169{
170 RT_NOREF(enmOp);
171 Assert(iOuter <= 1);
172 if (i == 0)
173 return 0;
174 if (i == 1)
175 return UINT16_MAX;
176 if (i == 2)
177 return iOp == 1 ? 0 : UINT16_MAX;
178 if (iOuter == 1 && iOp == 2)
179 return (uint16_t)(int16_t)(int8_t)RandU8(i, iOp);
180 if ((i % 3) == 0)
181 return (uint16_t)RTRandU32Ex(0, UINT16_MAX >> RTRandU32Ex(1, 11));
182 return (uint16_t)RTRandU32Ex(0, UINT16_MAX);
183}
184
185
186static uint32_t RandU32(unsigned i, unsigned iOp, unsigned iOuter, enum OPCODESX86 enmOp)
187{
188 RT_NOREF(enmOp);
189 Assert(iOuter <= 1);
190 if (i == 0)
191 return 0;
192 if (i == 1)
193 return UINT32_MAX;
194 if (i == 2)
195 return iOp == 1 ? 0 : UINT32_MAX;
196 if (i == 3)
197 {
198 /* Triggering OF with an 8-bit immediate operand is seriously difficult with pure
199 randomness, so cheat. */
200 switch (enmOp)
201 {
202 /* Both ops must have the same sign and the sign change. Pick positive to negative */
203 case OP_ADD:
204 case OP_ADC:
205 {
206 if (iOuter == 0)
207 return RTRandU32Ex(UINT32_C(0x40000000), UINT32_C(0x7fffffff));
208 if (iOp != 2)
209 return RTRandU32Ex(UINT32_C(0x7ffffff0), UINT32_C(0x7fffffff));
210 return RTRandU32Ex(0x10, 0x7f);
211 }
212
213 /* Pick positive left, negative right. */
214 case OP_SUB:
215 case OP_SBB:
216 case OP_CMP:
217 {
218 if (iOuter == 0)
219 return iOp != 2
220 ? RTRandU32Ex(UINT32_C(0x40000000), UINT32_C(0x7fffffff))
221 : RTRandU32Ex(UINT32_C(0x80000002), UINT32_C(0xc0000000));
222 if (iOp != 2)
223 return RTRandU32Ex(UINT32_C(0x7ffffff0), UINT32_C(0x7fffffff));
224 return RTRandU32Ex(UINT32_C(0xffffff81), UINT32_C(0xffffffef));
225 }
226
227 default:
228 break;
229 }
230 }
231 if (iOuter == 1 && iOp == 2)
232 return (uint32_t)(int32_t)(int8_t)RandU8(i, iOp);
233
234 if ((i % 5) == 0)
235 return RTRandU32Ex(0, UINT32_MAX >> RTRandU32Ex(1, 23));
236 return RTRandU32();
237}
238
239
240static uint64_t RandU64(unsigned i, unsigned iOp, unsigned iOuter, enum OPCODESX86 enmOp)
241{
242 RT_NOREF(enmOp);
243 if (i == 0)
244 return 0;
245 if (i == 1)
246 return UINT64_MAX;
247 if (i == 2)
248 return iOp == 1 ? 0 : UINT64_MAX;
249 if (i == 3)
250 {
251 /* Triggering OF with an 8-bit immediate operand is seriously difficult with pure
252 randomness, so cheat. */
253 switch (enmOp)
254 {
255 /* Both ops must have the same sign and the sign change. Pick positive to negative */
256 case OP_ADD:
257 case OP_ADC:
258 {
259 if (iOuter == 0)
260 return RTRandU64Ex(UINT64_C(0x4000000000000000), UINT64_C(0x7fffffffffffffff));
261 if (iOuter == 2) /* signed 32-bit immediate */
262 return iOp != 2
263 ? RTRandU64Ex(UINT64_C(0x7fffffffc0000000), UINT64_C(0x7fffffffffffffff))
264 : RTRandU64Ex(UINT64_C(0x0000000040000000), UINT64_C(0x000000007f000000));
265 /* signed 8-bit immediate */
266 return iOp != 2
267 ? RTRandU64Ex(UINT64_C(0x7ffffffffffffff0), UINT64_C(0x7fffffffffffffff))
268 : RTRandU64Ex(UINT64_C(0x0000000000000010), UINT64_C(0x000000000000007f));
269 }
270
271 /* Pick positive left, negative right. */
272 case OP_SUB:
273 case OP_SBB:
274 case OP_CMP:
275 {
276 if (iOuter == 0)
277 return iOp != 2
278 ? RTRandU64Ex(UINT64_C(0x4000000000000000), UINT64_C(0x7fffffffffffffff))
279 : RTRandU64Ex(UINT64_C(0x8000000000000002), UINT64_C(0xc000000000000000));
280 if (iOuter == 2) /* signed 32-bit immediate */
281 return iOp != 2
282 ? RTRandU64Ex(UINT64_C(0x7fffffffc0000002), UINT64_C(0x7fffffffffffffff))
283 : RTRandU64Ex(UINT64_C(0xffffffff80000002), UINT64_C(0xffffffffc0000000));
284 /* signed 8-bit immediate */
285 return iOp != 2
286 ? RTRandU64Ex(UINT64_C(0x7ffffffffffffff0), UINT64_C(0x7fffffffffffffff))
287 : RTRandU64Ex(UINT64_C(0xffffffffffffff81), UINT64_C(0xffffffffffffffef));
288 }
289
290 default:
291 break;
292 }
293 }
294 if (iOuter != 0 && iOp == 2)
295 {
296 Assert(iOuter <= 2);
297 if (iOuter == 1)
298 return (uint64_t)(int64_t)(int8_t)RTRandU32Ex(0, UINT8_MAX);
299 if ((i % 2) != 0)
300 return (uint64_t)(int32_t)RTRandU32();
301 int32_t i32 = (int32_t)RTRandU32Ex(0, UINT32_MAX >> RTRandU32Ex(1, 23));
302 if (RTRandU32Ex(0, 1) & 1)
303 i32 = -i32;
304 return (uint64_t)(int64_t)i32;
305 }
306 if ((i % 5) == 0)
307 return RTRandU64Ex(0, UINT64_MAX >> RTRandU32Ex(1, 55));
308 return RTRandU64();
309}
310
311
312DECL_FORCE_INLINE(uint32_t)
313EnsureEflCoverage(unsigned iTest, unsigned cTests, unsigned cActiveEfls, uint32_t fActiveEfl,
314 uint32_t fSet, uint32_t fClear, uint32_t *pfMustBeClear)
315{
316 *pfMustBeClear = 0;
317 unsigned cLeft = cTests - iTest;
318 if (cLeft > cActiveEfls * 2)
319 return 0;
320
321 /* Find out which flag we're checking for now. */
322 unsigned iBit = ASMBitFirstSetU32(fActiveEfl) - 1;
323 while (cLeft >= 2)
324 {
325 cLeft -= 2;
326 fActiveEfl &= ~RT_BIT_32(iBit);
327 iBit = ASMBitFirstSetU32(fActiveEfl) - 1;
328 }
329
330 if (cLeft & 1)
331 {
332 if (!(fSet & RT_BIT_32(iBit)))
333 return RT_BIT_32(iBit);
334 }
335 else if (!(fClear & RT_BIT_32(iBit)))
336 *pfMustBeClear = RT_BIT_32(iBit);
337 return 0;
338}
339
340
341static void FileHeader(PRTSTREAM pOut, const char *pszFilename, const char *pszIncludeBlocker)
342{
343 RTStrmPrintf(pOut,
344 "// ##### BEGINFILE \"%s\"\n"
345 "/* $" "Id$ */\n"
346 "/** @file\n"
347 " * BS3Kit - bs3-cpu-instr-2, %s - auto generated (do not edit).\n"
348 " */\n"
349 "\n"
350 "/*\n"
351 " * Copyright (C) 2024 Oracle and/or its affiliates.\n"
352 " *\n"
353 " * This file is part of VirtualBox base platform packages, as\n"
354 " * available from https://www.virtualbox.org.\n"
355 " *\n"
356 " * This program is free software; you can redistribute it and/or\n"
357 " * modify it under the terms of the GNU General Public License\n"
358 " * as published by the Free Software Foundation, in version 3 of the\n"
359 " * License.\n"
360 " *\n"
361 " * This program is distributed in the hope that it will be useful, but\n"
362 " * WITHOUT ANY WARRANTY; without even the implied warranty of\n"
363 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
364 " * General Public License for more details.\n"
365 " *\n"
366 " * You should have received a copy of the GNU General Public License\n"
367 " * along with this program; if not, see <https://www.gnu.org/licenses>.\n"
368 " *\n"
369 " * The contents of this file may alternatively be used under the terms\n"
370 " * of the Common Development and Distribution License Version 1.0\n"
371 " * (CDDL), a copy of it is provided in the \"COPYING.CDDL\" file included\n"
372 " * in the VirtualBox distribution, in which case the provisions of the\n"
373 " * CDDL are applicable instead of those of the GPL.\n"
374 " *\n"
375 " * You may elect to license modified versions of this file under the\n"
376 " * terms and conditions of either the GPL or the CDDL or both.\n"
377 " *\n"
378 " * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0\n"
379 " */\n"
380 "\n"
381 , pszFilename, pszFilename);
382 if (!pszIncludeBlocker)
383 RTStrmPrintf(pOut,
384 "#include <bs3kit.h>\n"
385 "#include \"bs3-cpu-instr-2.h\"\n");
386 else
387 RTStrmPrintf(pOut,
388 "#ifndef %s\n"
389 "#define %s\n"
390 "#ifndef RT_WITHOUT_PRAGMA_ONCE\n"
391 "# pragma once\n"
392 "#endif\n",
393 pszIncludeBlocker, pszIncludeBlocker);
394}
395
396int main(int argc, char **argv)
397{
398 RTR3InitExe(argc, &argv, 0);
399
400 /*
401 * Constants.
402 */
403 enum { kEflBeaviour_Intel = 0, kEflBeaviour_Amd }
404 const enmEflBehaviour = ASMIsAmdCpu() || ASMIsHygonCpu() ? kEflBeaviour_Amd : kEflBeaviour_Intel;
405 static const char * const s_apszEflBehaviourTabNm[] = { "intel_", "amd_" };
406
407 /*
408 * Parse arguments.
409 */
410 PRTSTREAM pOut = g_pStdOut;
411 unsigned cTestsU8 = 32;
412 unsigned cTestsU16 = 32;
413 unsigned cTestsU32 = 36;
414 unsigned cTestsU64 = 48;
415
416 /** @todo */
417 if (argc != 1)
418 {
419 RTMsgSyntax("No arguments expected");
420 return RTEXITCODE_SYNTAX;
421 }
422
423
424 /*
425 * Generate the test data.
426 */
427 static struct
428 {
429 const char *pszName;
430 enum OPCODESX86 enmOp;
431 DECLCALLBACKMEMBER(uint32_t, pfnU8, ( uint8_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint8_t *puResult));
432 DECLCALLBACKMEMBER(uint32_t, pfnU16,(uint16_t uSrc1, uint16_t uSrc2, uint32_t fCarry, uint16_t *puResult));
433 DECLCALLBACKMEMBER(uint32_t, pfnU32,(uint32_t uSrc1, uint32_t uSrc2, uint32_t fCarry, uint32_t *puResult));
434 DECLCALLBACKMEMBER(uint32_t, pfnU64,(uint64_t uSrc1, uint64_t uSrc2, uint32_t fCarry, uint64_t *puResult));
435 uint8_t cActiveEfls;
436 uint16_t fActiveEfls;
437 bool fCarryIn;
438 bool fImmVars;
439 } const s_aBinary[] =
440 {
441 { "and", OP_AND, GenU8_and, GenU16_and, GenU32_and, GenU64_and, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false, true },
442 { "or", OP_OR, GenU8_or, GenU16_or, GenU32_or, GenU64_or, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false, true },
443 { "xor", OP_XOR, GenU8_xor, GenU16_xor, GenU32_xor, GenU64_xor, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false, true },
444 { "test", OP_TEST, GenU8_test, GenU16_test, GenU32_test, GenU64_test, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false, true },
445
446 { "add", OP_ADD, GenU8_add, GenU16_add, GenU32_add, GenU64_add, 6, X86_EFL_STATUS_BITS, false, true },
447 { "adc", OP_ADC, GenU8_adc, GenU16_adc, GenU32_adc, GenU64_adc, 6, X86_EFL_STATUS_BITS, true, true },
448 { "sub", OP_SUB, GenU8_sub, GenU16_sub, GenU32_sub, GenU64_sub, 6, X86_EFL_STATUS_BITS, false, true },
449 { "sbb", OP_SBB, GenU8_sbb, GenU16_sbb, GenU32_sbb, GenU64_sbb, 6, X86_EFL_STATUS_BITS, true, true },
450 { "cmp", OP_CMP, GenU8_cmp, GenU16_cmp, GenU32_cmp, GenU64_cmp, 6, X86_EFL_STATUS_BITS, false, true },
451
452 { "bt", OP_BT, NULL, GenU16_bt, GenU32_bt, GenU64_bt, 1, X86_EFL_CF, false, false },
453 { "btc", OP_BTC, NULL, GenU16_btc, GenU32_btc, GenU64_btc, 1, X86_EFL_CF, false, false },
454 { "btr", OP_BTR, NULL, GenU16_btr, GenU32_btr, GenU64_btr, 1, X86_EFL_CF, false, false },
455 { "bts", OP_BTS, NULL, GenU16_bts, GenU32_bts, GenU64_bts, 1, X86_EFL_CF, false, false },
456 };
457
458 static struct
459 {
460 const char *pszName;
461 enum OPCODESX86 enmOp;
462 DECLCALLBACKMEMBER(uint32_t, pfnU8, ( uint8_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint8_t *puResult));
463 DECLCALLBACKMEMBER(uint32_t, pfnU16,(uint16_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint16_t *puResult));
464 DECLCALLBACKMEMBER(uint32_t, pfnU32,(uint32_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint32_t *puResult));
465 DECLCALLBACKMEMBER(uint32_t, pfnU64,(uint64_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint64_t *puResult));
466 DECLCALLBACKMEMBER(uint32_t, pfnU8Ib, ( uint8_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint8_t *puResult));
467 DECLCALLBACKMEMBER(uint32_t, pfnU16Ib,(uint16_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint16_t *puResult));
468 DECLCALLBACKMEMBER(uint32_t, pfnU32Ib,(uint32_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint32_t *puResult));
469 DECLCALLBACKMEMBER(uint32_t, pfnU64Ib,(uint64_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint64_t *puResult));
470 uint8_t cActiveEfls;
471 uint16_t fActiveEfls;
472 bool fCarryIn;
473 } const s_aShifters[] =
474 {
475 { "shl", OP_SHL, GenU8_shl, GenU16_shl, GenU32_shl, GenU64_shl, GenU8_shl_Ib, GenU16_shl_Ib, GenU32_shl_Ib, GenU64_shl_Ib, 6, X86_EFL_STATUS_BITS, false },
476 { "shr", OP_SHR, GenU8_shr, GenU16_shr, GenU32_shr, GenU64_shr, GenU8_shr_Ib, GenU16_shr_Ib, GenU32_shr_Ib, GenU64_shr_Ib, 6, X86_EFL_STATUS_BITS, false },
477 { "sar", OP_SAR, GenU8_sar, GenU16_sar, GenU32_sar, GenU64_sar, GenU8_sar_Ib, GenU16_sar_Ib, GenU32_sar_Ib, GenU64_sar_Ib, 6, X86_EFL_STATUS_BITS, false },
478 { "rol", OP_ROL, GenU8_rol, GenU16_rol, GenU32_rol, GenU64_rol, GenU8_rol_Ib, GenU16_rol_Ib, GenU32_rol_Ib, GenU64_rol_Ib, 2, X86_EFL_CF | X86_EFL_OF, false },
479 { "ror", OP_ROR, GenU8_ror, GenU16_ror, GenU32_ror, GenU64_ror, GenU8_ror_Ib, GenU16_ror_Ib, GenU32_ror_Ib, GenU64_ror_Ib, 2, X86_EFL_CF | X86_EFL_OF, false },
480 { "rcl", OP_RCL, GenU8_rcl, GenU16_rcl, GenU32_rcl, GenU64_rcl, GenU8_rcl_Ib, GenU16_rcl_Ib, GenU32_rcl_Ib, GenU64_rcl_Ib, 2, X86_EFL_CF | X86_EFL_OF, true },
481 { "rcr", OP_RCR, GenU8_rcr, GenU16_rcr, GenU32_rcr, GenU64_rcr, GenU8_rcr_Ib, GenU16_rcr_Ib, GenU32_rcr_Ib, GenU64_rcr_Ib, 2, X86_EFL_CF | X86_EFL_OF, true },
482 };
483
484 RTStrmPrintf(pOut, "\n"); /* filesplitter requires this. */
485
486 /*
487 * Header:
488 */
489 FileHeader(pOut, "bs3-cpu-instr-2-data.h", "VBOX_INCLUDED_SRC_bootsectors_bs3_cpu_instr_2_data_h");
490#define DO_ONE_TYPE(a_Entry, a_pszExtraNm, a_szTypeBaseNm, a_cBits) do { \
491 RTStrmPrintf(pOut, \
492 "\n" \
493 "extern const uint16_t g_cBs3CpuInstr2_%s_%sTestDataU" #a_cBits ";\n" \
494 "extern const " a_szTypeBaseNm #a_cBits " g_aBs3CpuInstr2_%s_%sTestDataU" #a_cBits "[];\n", \
495 a_Entry.pszName, a_pszExtraNm, a_Entry.pszName, a_pszExtraNm); \
496 } while (0)
497 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aBinary); iInstr++)
498 {
499 if (s_aBinary[iInstr].pfnU8)
500 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", 8);
501 if (s_aBinary[iInstr].pfnU16)
502 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", 16);
503 if (s_aBinary[iInstr].pfnU32)
504 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", 32);
505 if (s_aBinary[iInstr].pfnU64)
506 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", 64);
507 }
508
509 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aShifters); iInstr++)
510 for (unsigned iEflBehaviour = 0; iEflBehaviour < RT_ELEMENTS(s_apszEflBehaviourTabNm); iEflBehaviour++)
511 {
512 DO_ONE_TYPE(s_aShifters[iInstr], s_apszEflBehaviourTabNm[iEflBehaviour], "BS3CPUINSTR2SHIFT", 8);
513 DO_ONE_TYPE(s_aShifters[iInstr], s_apszEflBehaviourTabNm[iEflBehaviour], "BS3CPUINSTR2SHIFT", 16);
514 DO_ONE_TYPE(s_aShifters[iInstr], s_apszEflBehaviourTabNm[iEflBehaviour], "BS3CPUINSTR2SHIFT", 32);
515 DO_ONE_TYPE(s_aShifters[iInstr], s_apszEflBehaviourTabNm[iEflBehaviour], "BS3CPUINSTR2SHIFT", 64);
516 }
517#undef DO_ONE_TYPE
518
519 RTStrmPrintf(pOut,
520 "\n"
521 "#endif /* !VBOX_INCLUDED_SRC_bootsectors_bs3_cpu_instr_2_data_h */\n"
522 "\n// ##### ENDFILE\n");
523
524#define DO_ONE_TYPE(a_Entry, a_pszExtraNm, a_szTypeBaseNm, a_ValueType, a_cBits, a_szFmt, a_pfnMember, a_cTests, a_fImmVars, a_fShift, a_pfnMemberIb) do { \
525 unsigned const cOuterLoops = 1 + a_fImmVars * (a_cBits == 64 ? 2 : a_cBits != 8 ? 1 : 0); \
526 unsigned const cTestFactor = !a_Entry.fCarryIn ? 1 : 2; \
527 unsigned cFunnyImm = 0; \
528 RTStrmPrintf(pOut, \
529 "\n" \
530 "const uint16_t g_cBs3CpuInstr2_%s_%sTestDataU" #a_cBits " = %u;\n" \
531 "const " a_szTypeBaseNm #a_cBits " g_aBs3CpuInstr2_%s_%sTestDataU" #a_cBits "[%u] =\n" \
532 "{\n", \
533 a_Entry.pszName, a_pszExtraNm, a_cTests * cTestFactor * cOuterLoops, \
534 a_Entry.pszName, a_pszExtraNm, a_cTests * cTestFactor * cOuterLoops); \
535 for (unsigned iOuter = 0; iOuter < cOuterLoops; iOuter++) \
536 { \
537 if (iOuter != 0) \
538 RTStrmPrintf(pOut, " /* r/m" #a_cBits", imm%u: */\n", iOuter == 1 ? 8 : 32); \
539 uint32_t fSet = 0; \
540 uint32_t fClear = 0; \
541 uint32_t uShiftTracker = 0; \
542 for (unsigned iTest = 0; iTest < a_cTests; iTest++) \
543 { \
544 uint32_t fMustBeClear = 0; \
545 uint32_t fMustBeSet = EnsureEflCoverage(iTest, a_cTests, a_Entry.cActiveEfls, \
546 a_Entry.fActiveEfls, fSet, fClear, &fMustBeClear); \
547 for (unsigned iTry = 0;; iTry++) \
548 { \
549 a_ValueType const uSrc1 = RandU##a_cBits(iTest + iTry, 1, iOuter, a_Entry.enmOp); \
550 a_ValueType const uSrc2 = !(a_fShift) ? RandU##a_cBits(iTest + iTry, 2, iOuter, a_Entry.enmOp) \
551 : RandU8Shift(iTest + iTry, a_cTests, &uShiftTracker, a_cBits); \
552 a_ValueType uResult = 0; \
553 uint32_t const fEflIn = !(a_fShift) ? 0 /*fCarry*/ : a_Entry.fCarryIn \
554 ? RandEflStatus() & ~(uint32_t)X86_EFL_CF : RandEflStatus(); \
555 uint32_t fEflOut = a_Entry.a_pfnMember(uSrc1, uSrc2, fEflIn, &uResult) \
556 & X86_EFL_STATUS_BITS; \
557 if ((fEflOut & fMustBeClear) || (~fEflOut & fMustBeSet)) \
558 { \
559 if (iTry < _1M) \
560 continue; \
561 RTMsgWarning("Giving up: " #a_cBits "-bit %s - fMustBeClear=%#x fMustBeSet=%#x iTest=%#x iTry=%#x iOuter=%d\n", \
562 a_Entry.pszName, fMustBeClear, fMustBeSet, iTest, iTry, iOuter); \
563 } \
564 fSet |= fEflOut; \
565 fClear |= ~fEflOut; \
566 if (!(a_fShift)) \
567 RTStrmPrintf(pOut, " { " a_szFmt ", " a_szFmt ", " a_szFmt ", %#05RX16 },\n", \
568 uSrc1, uSrc2, uResult, fEflOut); \
569 else \
570 { \
571 /* Seems that 'rol reg,Ib' & 'ror reg,Ib' produces different OF results on intel. \
572 Observed on 8700B, 9980HK, 10980xe, 1260p, ++. */ \
573 a_ValueType uResultIb = 0; \
574 uint32_t const fEflOutIb = a_Entry.a_pfnMemberIb(uSrc1, uSrc2, fEflIn, &uResultIb) \
575 & X86_EFL_STATUS_BITS; \
576 if ((fEflOutIb & X86_EFL_OF) != (fEflOut & X86_EFL_OF)) cFunnyImm += 1; \
577 if (uResultIb != uResult) RT_BREAKPOINT(); \
578 if ((fEflOutIb ^ fEflOut) & (X86_EFL_STATUS_BITS & ~X86_EFL_OF)) RT_BREAKPOINT(); \
579 if (fEflOutIb & X86_EFL_OF) fEflOut |= RT_BIT_32(BS3CPUINSTR2SHIFT_EFL_IB_OVERFLOW_OUT_BIT); \
580 RTStrmPrintf(pOut, " { " a_szFmt ", %#04RX8, %#05RX16, " a_szFmt ", %#05RX16 },%s\n", \
581 uSrc1, (uint8_t)uSrc2, (uint16_t)fEflIn, uResult, (uint16_t)fEflOut, \
582 (fEflOut ^ fEflOutIb) & X86_EFL_OF ? " /* OF/Ib */" : ""); \
583 } \
584 if (a_Entry.fCarryIn) \
585 { \
586 uResult = 0; \
587 fEflOut = a_Entry.a_pfnMember(uSrc1, uSrc2, fEflIn | X86_EFL_CF, &uResult) & X86_EFL_STATUS_BITS; \
588 fSet |= fEflOut; \
589 fClear |= ~fEflOut; \
590 if (!(a_fShift)) \
591 RTStrmPrintf(pOut, " { " a_szFmt ", " a_szFmt ", " a_szFmt ", %#05RX16 },\n", uSrc1, uSrc2, \
592 uResult, (uint16_t)(fEflOut | RT_BIT_32(BS3CPUINSTR2BIN_EFL_CARRY_IN_BIT))); \
593 else \
594 { \
595 /* Seems that 'rol reg,Ib' & 'ror reg,Ib' produces different OF results on intel. \
596 Observed on 8700B, 9980HK, 10980xe, 1260p, ++. */ \
597 a_ValueType uResultIb = 0; \
598 uint32_t const fEflOutIb = a_Entry.a_pfnMemberIb(uSrc1, uSrc2, fEflIn | X86_EFL_CF, &uResultIb) \
599 & X86_EFL_STATUS_BITS; \
600 if ((fEflOutIb & X86_EFL_OF) != (fEflOut & X86_EFL_OF)) cFunnyImm += 1; \
601 if (uResultIb != uResult) RT_BREAKPOINT(); \
602 if ((fEflOutIb ^ fEflOut) & (X86_EFL_STATUS_BITS & ~X86_EFL_OF)) RT_BREAKPOINT(); \
603 if (fEflOutIb & X86_EFL_OF) fEflOut |= RT_BIT_32(BS3CPUINSTR2SHIFT_EFL_IB_OVERFLOW_OUT_BIT); \
604 RTStrmPrintf(pOut, " { " a_szFmt ", %#04RX8, %#05RX16, " a_szFmt ", %#05RX16 },%s\n", \
605 uSrc1, (uint8_t)uSrc2, (uint16_t)(fEflIn | X86_EFL_CF), uResult, \
606 (uint16_t)fEflOut, (fEflOut ^ fEflOutIb) & X86_EFL_OF ? " /* OF/Ib */" : ""); \
607 } \
608 } \
609 break; \
610 } \
611 } \
612 } \
613 if (cFunnyImm == 0) \
614 RTStrmPrintf(pOut, "};\n"); \
615 else \
616 RTStrmPrintf(pOut, "}; /* Note! " #a_cBits "-bit %s reg,imm8 results differed %u times from the other form */\n", \
617 a_Entry.pszName, cFunnyImm); \
618 } while (0)
619
620 /*
621 * Source: 8, 16 & 32 bit data.
622 */
623 FileHeader(pOut, "bs3-cpu-instr-2-data16.c16", NULL);
624 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aBinary); iInstr++)
625 {
626 if (s_aBinary[iInstr].pfnU8)
627 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", uint8_t, 8, "%#04RX8", pfnU8, cTestsU8, s_aBinary[iInstr].fImmVars, 0, pfnU8);
628 if (s_aBinary[iInstr].pfnU16)
629 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", uint16_t, 16, "%#06RX16", pfnU16, cTestsU16, s_aBinary[iInstr].fImmVars, 0, pfnU16);
630 if (s_aBinary[iInstr].pfnU32)
631 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", uint32_t, 32, "%#010RX32", pfnU32, cTestsU32, s_aBinary[iInstr].fImmVars, 0, pfnU32);
632 }
633 RTStrmPrintf(pOut, "\n// ##### ENDFILE\n");
634
635 /*
636 * Source: 64 bit data (goes in different data segment).
637 */
638 FileHeader(pOut, "bs3-cpu-instr-2-data64.c64", NULL);
639 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aBinary); iInstr++)
640 if (s_aBinary[iInstr].pfnU64)
641 DO_ONE_TYPE(s_aBinary[iInstr], "", "BS3CPUINSTR2BIN", uint64_t, 64, "%#018RX64", pfnU64, cTestsU64, s_aBinary[iInstr].fImmVars, 0, pfnU64);
642 RTStrmPrintf(pOut, "\n// ##### ENDFILE\n");
643
644
645 /*
646 * Source: 8, 16 & 32 bit data for the host CPU.
647 */
648 const char * const pszEflTabNm = s_apszEflBehaviourTabNm[enmEflBehaviour];
649 FileHeader(pOut, enmEflBehaviour == kEflBeaviour_Amd ? "bs3-cpu-instr-2-data16-amd.c16" : "bs3-cpu-instr-2-data16-intel.c16", NULL);
650 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aShifters); iInstr++)
651 {
652 DO_ONE_TYPE(s_aShifters[iInstr], pszEflTabNm, "BS3CPUINSTR2SHIFT", uint8_t, 8, "%#04RX8", pfnU8, cTestsU8, 0, 1, pfnU8Ib);
653 DO_ONE_TYPE(s_aShifters[iInstr], pszEflTabNm, "BS3CPUINSTR2SHIFT", uint16_t, 16, "%#06RX16", pfnU16, cTestsU16, 0, 1, pfnU16Ib);
654 DO_ONE_TYPE(s_aShifters[iInstr], pszEflTabNm, "BS3CPUINSTR2SHIFT", uint32_t, 32, "%#010RX32", pfnU32, cTestsU32, 0, 1, pfnU32Ib);
655 }
656 RTStrmPrintf(pOut, "\n// ##### ENDFILE\n");
657
658 /*
659 * Source: 64 bit data for the host CPU (goes in different data segment).
660 */
661 FileHeader(pOut, enmEflBehaviour == kEflBeaviour_Amd ? "bs3-cpu-instr-2-data64-amd.c64" : "bs3-cpu-instr-2-data64-intel.c64", NULL);
662 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aShifters); iInstr++)
663 DO_ONE_TYPE(s_aShifters[iInstr], pszEflTabNm, "BS3CPUINSTR2SHIFT", uint64_t, 64, "%#018RX64", pfnU64, cTestsU64, 0, 1, pfnU64Ib);
664 RTStrmPrintf(pOut, "\n// ##### ENDFILE\n");
665
666#undef DO_ONE_TYPE
667
668 return 0;
669}
670
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette