VirtualBox

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

Last change on this file since 103608 was 103608, checked in by vboxsync, 12 months ago

ValKit/bs3-cpu-instr-2: Added a bunch of tests for binary arithmetic/logical/bit-test-modify instruction (add, sub, cmp, test, and, ...). (This is a little reminiscent of early tstIEMAImpl, but we're severly space limited here, so don't worry about the data source-file size or compile times.) [build fix] bugref:10376

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.3 KB
Line 
1/* $Id: bs3-cpu-instr-2-gen.cpp 103608 2024-02-29 02:20:34Z 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/asm.h>
42#include <iprt/initterm.h>
43#include <iprt/message.h>
44#include <iprt/rand.h>
45#include <iprt/stream.h>
46#include <iprt/x86.h>
47#include "bs3-cpu-instr-2.h"
48
49
50/*********************************************************************************************************************************
51* External Functions *
52*********************************************************************************************************************************/
53#define PROTOTYPE_BINARY(a_Ins) \
54 DECLASM(uint32_t) RT_CONCAT(GenU8_,a_Ins)( uint8_t, uint8_t, uint32_t, uint8_t *); \
55 DECLASM(uint32_t) RT_CONCAT(GenU16_,a_Ins)(uint16_t, uint16_t, uint32_t, uint16_t *); \
56 DECLASM(uint32_t) RT_CONCAT(GenU32_,a_Ins)(uint32_t, uint32_t, uint32_t, uint32_t *); \
57 DECLASM(uint32_t) RT_CONCAT(GenU64_,a_Ins)(uint64_t, uint64_t, uint32_t, uint64_t *)
58
59PROTOTYPE_BINARY(and);
60PROTOTYPE_BINARY(or);
61PROTOTYPE_BINARY(xor);
62PROTOTYPE_BINARY(test);
63
64PROTOTYPE_BINARY(add);
65PROTOTYPE_BINARY(adc);
66PROTOTYPE_BINARY(sub);
67PROTOTYPE_BINARY(sbb);
68PROTOTYPE_BINARY(cmp);
69
70PROTOTYPE_BINARY(bt);
71PROTOTYPE_BINARY(btc);
72PROTOTYPE_BINARY(btr);
73PROTOTYPE_BINARY(bts);
74
75
76static uint8_t RandU8(unsigned i, unsigned iOp)
77{
78 if (i == 0)
79 return 0;
80 if (i == 1)
81 return UINT8_MAX;
82 if (i == 2)
83 return iOp == 1 ? 0 : UINT8_MAX;
84 return (uint8_t)RTRandU32Ex(0, UINT8_MAX);
85}
86
87
88static uint16_t RandU16(unsigned i, unsigned iOp)
89{
90 if (i == 0)
91 return 0;
92 if (i == 1)
93 return UINT16_MAX;
94 if (i == 2)
95 return iOp == 1 ? 0 : UINT16_MAX;
96 if ((i % 3) == 0)
97 return (uint16_t)RTRandU32Ex(0, UINT16_MAX >> RTRandU32Ex(1, 11));
98 return (uint16_t)RTRandU32Ex(0, UINT16_MAX);
99}
100
101
102static uint32_t RandU32(unsigned i, unsigned iOp)
103{
104 if (i == 0)
105 return 0;
106 if (i == 1)
107 return UINT32_MAX;
108 if (i == 2)
109 return iOp == 1 ? 0 : UINT32_MAX;
110 if ((i % 3) == 0)
111 return RTRandU32Ex(0, UINT32_MAX >> RTRandU32Ex(1, 23));
112 return RTRandU32();
113}
114
115
116static uint64_t RandU64(unsigned i, unsigned iOp)
117{
118 if (i == 0)
119 return 0;
120 if (i == 1)
121 return UINT64_MAX;
122 if (i == 2)
123 return iOp == 1 ? 0 : UINT64_MAX;
124 if ((i % 3) == 0)
125 return RTRandU64Ex(0, UINT64_MAX >> RTRandU32Ex(1, 55));
126 return RTRandU64();
127}
128
129
130DECL_FORCE_INLINE(uint32_t)
131EnsureEflCoverage(unsigned iTest, unsigned cTests, unsigned cActiveEfls, uint32_t fActiveEfl,
132 uint32_t fSet, uint32_t fClear, uint32_t *pfMustBeClear)
133{
134 *pfMustBeClear = 0;
135 unsigned cLeft = cTests - iTest;
136 if (cLeft > cActiveEfls * 2)
137 return 0;
138
139 /* Find out which flag we're checking for now. */
140 unsigned iBit = ASMBitFirstSetU32(fActiveEfl) - 1;
141 while (cLeft >= 2)
142 {
143 cLeft -= 2;
144 fActiveEfl &= ~RT_BIT_32(iBit);
145 iBit = ASMBitFirstSetU32(fActiveEfl) - 1;
146 }
147
148 if (cLeft & 1)
149 {
150 if (!(fSet & RT_BIT_32(iBit)))
151 return RT_BIT_32(iBit);
152 }
153 else if (!(fClear & RT_BIT_32(iBit)))
154 *pfMustBeClear = RT_BIT_32(iBit);
155 return 0;
156}
157
158
159static void FileHeader(PRTSTREAM pOut, const char *pszFilename, const char *pszIncludeBlocker)
160{
161 RTStrmPrintf(pOut,
162 "// ##### BEGINFILE \"%s\"\n"
163 "/* $" "Id$ */\n"
164 "/** @file\n"
165 " * BS3Kit - bs3-cpu-instr-2, %s - auto generated (do not edit).\n"
166 " */\n"
167 "\n"
168 "/*\n"
169 " * Copyright (C) 2024 Oracle and/or its affiliates.\n"
170 " *\n"
171 " * This file is part of VirtualBox base platform packages, as\n"
172 " * available from https://www.virtualbox.org.\n"
173 " *\n"
174 " * This program is free software; you can redistribute it and/or\n"
175 " * modify it under the terms of the GNU General Public License\n"
176 " * as published by the Free Software Foundation, in version 3 of the\n"
177 " * License.\n"
178 " *\n"
179 " * This program is distributed in the hope that it will be useful, but\n"
180 " * WITHOUT ANY WARRANTY; without even the implied warranty of\n"
181 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
182 " * General Public License for more details.\n"
183 " *\n"
184 " * You should have received a copy of the GNU General Public License\n"
185 " * along with this program; if not, see <https://www.gnu.org/licenses>.\n"
186 " *\n"
187 " * The contents of this file may alternatively be used under the terms\n"
188 " * of the Common Development and Distribution License Version 1.0\n"
189 " * (CDDL), a copy of it is provided in the \"COPYING.CDDL\" file included\n"
190 " * in the VirtualBox distribution, in which case the provisions of the\n"
191 " * CDDL are applicable instead of those of the GPL.\n"
192 " *\n"
193 " * You may elect to license modified versions of this file under the\n"
194 " * terms and conditions of either the GPL or the CDDL or both.\n"
195 " *\n"
196 " * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0\n"
197 " */\n"
198 "\n"
199 , pszFilename, pszFilename);
200 if (!pszIncludeBlocker)
201 RTStrmPrintf(pOut,
202 "#include <bs3kit.h>\n"
203 "#include \"bs3-cpu-instr-2.h\"\n");
204 else
205 RTStrmPrintf(pOut,
206 "#ifndef %s\n"
207 "#define %s\n"
208 "#ifndef RT_WITHOUT_PRAGMA_ONCE\n"
209 "# pragma once\n"
210 "#endif\n",
211 pszIncludeBlocker, pszIncludeBlocker);
212}
213
214int main(int argc, char **argv)
215{
216 RTR3InitExe(argc, &argv, 0);
217
218 /*
219 * Parse arguments.
220 */
221 PRTSTREAM pOut = g_pStdOut;
222 unsigned cTestsU8 = 48;
223 unsigned cTestsU16 = 48;
224 unsigned cTestsU32 = 48;
225 unsigned cTestsU64 = 64;
226
227 /** @todo */
228 if (argc != 1)
229 {
230 RTMsgSyntax("No arguments expected");
231 return RTEXITCODE_SYNTAX;
232 }
233
234
235 /*
236 * Generate the test data.
237 */
238 static struct
239 {
240 const char *pszName;
241 DECLCALLBACKMEMBER(uint32_t, pfnU8, ( uint8_t uSrc1, uint8_t uSrc2, uint32_t fCarry, uint8_t *puResult));
242 DECLCALLBACKMEMBER(uint32_t, pfnU16,(uint16_t uSrc1, uint16_t uSrc2, uint32_t fCarry, uint16_t *puResult));
243 DECLCALLBACKMEMBER(uint32_t, pfnU32,(uint32_t uSrc1, uint32_t uSrc2, uint32_t fCarry, uint32_t *puResult));
244 DECLCALLBACKMEMBER(uint32_t, pfnU64,(uint64_t uSrc1, uint64_t uSrc2, uint32_t fCarry, uint64_t *puResult));
245 uint8_t cActiveEfls;
246 uint16_t fActiveEfls;
247 bool fCarryIn;
248 } const s_aInstr[] =
249 {
250 { "and", GenU8_and, GenU16_and, GenU32_and, GenU64_and, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false },
251 { "or", GenU8_or, GenU16_or, GenU32_or, GenU64_or, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false },
252 { "xor", GenU8_xor, GenU16_xor, GenU32_xor, GenU64_xor, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false },
253 { "test", GenU8_test, GenU16_test, GenU32_test, GenU64_test, 3, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF, false },
254
255 { "add", GenU8_add, GenU16_add, GenU32_add, GenU64_add, 6, X86_EFL_STATUS_BITS, false },
256 { "adc", GenU8_adc, GenU16_adc, GenU32_adc, GenU64_adc, 6, X86_EFL_STATUS_BITS, true },
257 { "sub", GenU8_sub, GenU16_sub, GenU32_sub, GenU64_sub, 6, X86_EFL_STATUS_BITS, false },
258 { "sbb", GenU8_sbb, GenU16_sbb, GenU32_sbb, GenU64_sbb, 6, X86_EFL_STATUS_BITS, true },
259 { "cmp", GenU8_cmp, GenU16_cmp, GenU32_cmp, GenU64_cmp, 6, X86_EFL_STATUS_BITS, false },
260
261 { "bt", NULL, GenU16_bt, GenU32_bt, GenU64_bt, 1, X86_EFL_CF, false },
262 { "btc", NULL, GenU16_btc, GenU32_btc, GenU64_btc, 1, X86_EFL_CF, false },
263 { "btr", NULL, GenU16_btr, GenU32_btr, GenU64_btr, 1, X86_EFL_CF, false },
264 { "bts", NULL, GenU16_bts, GenU32_bts, GenU64_bts, 1, X86_EFL_CF, false },
265 };
266
267 RTStrmPrintf(pOut, "\n"); /* filesplitter requires this. */
268
269 /* Header: */
270 FileHeader(pOut, "bs3-cpu-instr-2-data.h", "VBOX_INCLUDED_SRC_bootsectors_bs3_cpu_instr_2_data_h");
271 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aInstr); iInstr++)
272 {
273#define DO_ONE_TYPE(a_ValueType, a_cBits, a_szFmt, a_pfnMember, a_cTests) do { \
274 RTStrmPrintf(pOut, \
275 "\n" \
276 "extern const unsigned g_cBs3CpuInstr2_%s_TestDataU" #a_cBits ";\n" \
277 "extern const BS3CPUINSTR2BIN" #a_cBits " g_aBs3CpuInstr2_%s_TestDataU" #a_cBits "[];\n", \
278 s_aInstr[iInstr].pszName, s_aInstr[iInstr].pszName); \
279 } while (0)
280 if (s_aInstr[iInstr].pfnU8)
281 DO_ONE_TYPE(uint8_t, 8, "%#04RX8", pfnU8, cTestsU8);
282 if (s_aInstr[iInstr].pfnU16)
283 DO_ONE_TYPE(uint16_t, 16, "%#06RX16", pfnU16, cTestsU16);
284 if (s_aInstr[iInstr].pfnU32)
285 DO_ONE_TYPE(uint32_t, 32, "%#010RX32", pfnU32, cTestsU32);
286 if (s_aInstr[iInstr].pfnU64)
287 DO_ONE_TYPE(uint64_t, 64, "%#018RX64", pfnU64, cTestsU64);
288#undef DO_ONE_TYPE
289 }
290 RTStrmPrintf(pOut,
291 "\n"
292 "#endif /* !VBOX_INCLUDED_SRC_bootsectors_bs3_cpu_instr_2_data_h */\n"
293 "\n// ##### ENDFILE\n");
294
295#define DO_ONE_TYPE(a_ValueType, a_cBits, a_szFmt, a_pfnMember, a_cTests) do { \
296 unsigned const cTestFactor = !s_aInstr[iInstr].fCarryIn ? 1 : 2; \
297 RTStrmPrintf(pOut, \
298 "\n" \
299 "const unsigned g_cBs3CpuInstr2_%s_TestDataU" #a_cBits " = %u;\n" \
300 "const BS3CPUINSTR2BIN" #a_cBits " g_aBs3CpuInstr2_%s_TestDataU" #a_cBits "[%u] =\n" \
301 "{\n", \
302 s_aInstr[iInstr].pszName, a_cTests * cTestFactor, \
303 s_aInstr[iInstr].pszName, a_cTests * cTestFactor); \
304 uint32_t fSet = 0; \
305 uint32_t fClear = 0; \
306 for (unsigned iTest = 0; iTest < a_cTests; iTest++) \
307 { \
308 uint32_t fMustBeClear = 0; \
309 uint32_t fMustBeSet = EnsureEflCoverage(iTest, a_cTests, s_aInstr[iInstr].cActiveEfls, \
310 s_aInstr[iInstr].fActiveEfls, fSet, fClear, &fMustBeClear); \
311 for (unsigned iTry = 0;; iTry++) \
312 { \
313 a_ValueType const uSrc1 = RandU##a_cBits(iTest + iTry, 1); \
314 a_ValueType const uSrc2 = RandU##a_cBits(iTest + iTry, 2); \
315 a_ValueType uResult = 0; \
316 uint32_t fEflOut = s_aInstr[iInstr].a_pfnMember(uSrc1, uSrc2, 0 /*fCarry*/, &uResult) \
317 & X86_EFL_STATUS_BITS; \
318 if (iTry < _1M && ((fEflOut & fMustBeClear) || (~fEflOut & fMustBeSet))) \
319 continue; \
320 fSet |= fEflOut; \
321 fClear |= ~fEflOut; \
322 RTStrmPrintf(pOut, " { " a_szFmt ", " a_szFmt ", " a_szFmt ", %#05RX16 },\n", \
323 uSrc1, uSrc2, uResult, fEflOut); \
324 if (s_aInstr[iInstr].fCarryIn) \
325 { \
326 uResult = 0; \
327 fEflOut = s_aInstr[iInstr].a_pfnMember(uSrc1, uSrc2, X86_EFL_CF, &uResult) & X86_EFL_STATUS_BITS; \
328 fSet |= fEflOut; \
329 fClear |= ~fEflOut; \
330 RTStrmPrintf(pOut, " { " a_szFmt ", " a_szFmt ", " a_szFmt ", %#05RX16 },\n", \
331 uSrc1, uSrc2, uResult, (fEflOut | RT_BIT_32(BS3CPUINSTR2BIN_EFL_CARRY_IN_BIT))); \
332 } \
333 break; \
334 } \
335 } \
336 RTStrmPrintf(pOut, \
337 "};\n"); \
338 } while (0)
339
340 /* Source: 8, 16 & 32 bit data. */
341 FileHeader(pOut, "bs3-cpu-instr-2-data16.c16", NULL);
342 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aInstr); iInstr++)
343 {
344 if (s_aInstr[iInstr].pfnU8)
345 DO_ONE_TYPE(uint8_t, 8, "%#04RX8", pfnU8, cTestsU8);
346 if (s_aInstr[iInstr].pfnU16)
347 DO_ONE_TYPE(uint16_t, 16, "%#06RX16", pfnU16, cTestsU16);
348 if (s_aInstr[iInstr].pfnU32)
349 DO_ONE_TYPE(uint32_t, 32, "%#010RX32", pfnU32, cTestsU32);
350 }
351 RTStrmPrintf(pOut, "\n// ##### ENDFILE\n");
352
353 /* Source: 64 bit data (goes in different data segment). */
354 FileHeader(pOut, "bs3-cpu-instr-2-data64.c64", NULL);
355 for (unsigned iInstr = 0; iInstr < RT_ELEMENTS(s_aInstr); iInstr++)
356 if (s_aInstr[iInstr].pfnU64)
357 DO_ONE_TYPE(uint64_t, 64, "%#018RX64", pfnU64, cTestsU64);
358 RTStrmPrintf(pOut, "\n// ##### ENDFILE\n");
359#undef DO_ONE_TYPE
360
361 return 0;
362}
363
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