VirtualBox

source: vbox/trunk/src/VBox/VMM/testcase/Instructions/InstructionTestGen.py@ 49368

Last change on this file since 49368 was 48346, checked in by vboxsync, 11 years ago

header fixes

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 86.9 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: InstructionTestGen.py 48346 2013-09-06 09:50:19Z vboxsync $
4
5"""
6Instruction Test Generator.
7"""
8
9from __future__ import print_function;
10
11__copyright__ = \
12"""
13Copyright (C) 2012-2013 Oracle Corporation
14
15This file is part of VirtualBox Open Source Edition (OSE), as
16available from http://www.virtualbox.org. This file is free software;
17you can redistribute it and/or modify it under the terms of the GNU
18General Public License (GPL) as published by the Free Software
19Foundation, in version 2 as it comes in the "COPYING" file of the
20VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22"""
23__version__ = "$Revision: 48346 $";
24
25
26# pylint: disable=C0103,R0913
27
28
29# Standard python imports.
30import io;
31import os;
32from optparse import OptionParser
33import random;
34import sys;
35
36
37## @name Exit codes
38## @{
39RTEXITCODE_SUCCESS = 0;
40RTEXITCODE_SYNTAX = 2;
41## @}
42
43## @name Various C macros we're used to.
44## @{
45UINT8_MAX = 0xff
46UINT16_MAX = 0xffff
47UINT32_MAX = 0xffffffff
48UINT64_MAX = 0xffffffffffffffff
49def RT_BIT_32(iBit): # pylint: disable=C0103
50 """ 32-bit one bit mask. """
51 return 1 << iBit;
52def RT_BIT_64(iBit): # pylint: disable=C0103
53 """ 64-bit one bit mask. """
54 return 1 << iBit;
55## @}
56
57
58## @name ModR/M
59## @{
60X86_MODRM_RM_MASK = 0x07;
61X86_MODRM_REG_MASK = 0x38;
62X86_MODRM_REG_SMASK = 0x07;
63X86_MODRM_REG_SHIFT = 3;
64X86_MODRM_MOD_MASK = 0xc0;
65X86_MODRM_MOD_SMASK = 0x03;
66X86_MODRM_MOD_SHIFT = 6;
67## @}
68
69## @name SIB
70## @{
71X86_SIB_BASE_MASK = 0x07;
72X86_SIB_INDEX_MASK = 0x38;
73X86_SIB_INDEX_SMASK = 0x07;
74X86_SIB_INDEX_SHIFT = 3;
75X86_SIB_SCALE_MASK = 0xc0;
76X86_SIB_SCALE_SMASK = 0x03;
77X86_SIB_SCALE_SHIFT = 6;
78## @}
79
80## @name Prefixes
81## @
82X86_OP_PRF_CS = 0x2e;
83X86_OP_PRF_SS = 0x36;
84X86_OP_PRF_DS = 0x3e;
85X86_OP_PRF_ES = 0x26;
86X86_OP_PRF_FS = 0x64;
87X86_OP_PRF_GS = 0x65;
88X86_OP_PRF_SIZE_OP = 0x66;
89X86_OP_PRF_SIZE_ADDR = 0x67;
90X86_OP_PRF_LOCK = 0xf0;
91X86_OP_PRF_REPZ = 0xf2;
92X86_OP_PRF_REPNZ = 0xf3;
93X86_OP_REX_B = 0x41;
94X86_OP_REX_X = 0x42;
95X86_OP_REX_R = 0x44;
96X86_OP_REX_W = 0x48;
97## @}
98
99
100## @name General registers
101## @
102X86_GREG_xAX = 0
103X86_GREG_xCX = 1
104X86_GREG_xDX = 2
105X86_GREG_xBX = 3
106X86_GREG_xSP = 4
107X86_GREG_xBP = 5
108X86_GREG_xSI = 6
109X86_GREG_xDI = 7
110X86_GREG_x8 = 8
111X86_GREG_x9 = 9
112X86_GREG_x10 = 10
113X86_GREG_x11 = 11
114X86_GREG_x12 = 12
115X86_GREG_x13 = 13
116X86_GREG_x14 = 14
117X86_GREG_x15 = 15
118## @}
119
120
121## @name Register names.
122## @{
123g_asGRegs64NoSp = ('rax', 'rcx', 'rdx', 'rbx', None, 'rbp', 'rsi', 'rdi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15');
124g_asGRegs64 = ('rax', 'rcx', 'rdx', 'rbx', 'rsp', 'rbp', 'rsi', 'rdi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15');
125g_asGRegs32NoSp = ('eax', 'ecx', 'edx', 'ebx', None, 'ebp', 'esi', 'edi',
126 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d');
127g_asGRegs32 = ('eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi',
128 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d');
129g_asGRegs16NoSp = ('ax', 'cx', 'dx', 'bx', None, 'bp', 'si', 'di',
130 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w');
131g_asGRegs16 = ('ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di',
132 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w');
133g_asGRegs8 = ('al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh');
134g_asGRegs8Rex = ('al', 'cl', 'dl', 'bl', 'spl', 'bpl', 'sil', 'dil',
135 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b',
136 'ah', 'ch', 'dh', 'bh');
137## @}
138
139
140## @name Random
141## @{
142g_iMyRandSeed = int((os.urandom(4)).encode('hex'), 16);
143#g_iMyRandSeed = 286523426;
144#g_iMyRandSeed = 1994382324;
145g_oMyRand = random.Random(g_iMyRandSeed);
146#g_oMyRand = random.SystemRandom();
147
148def randU8():
149 """ Unsigned 8-bit random number. """
150 return g_oMyRand.getrandbits(8);
151
152def randU16():
153 """ Unsigned 16-bit random number. """
154 return g_oMyRand.getrandbits(16);
155
156def randU32():
157 """ Unsigned 32-bit random number. """
158 return g_oMyRand.getrandbits(32);
159
160def randU64():
161 """ Unsigned 64-bit random number. """
162 return g_oMyRand.getrandbits(64);
163
164def randUxx(cBits):
165 """ Unsigned 8-, 16-, 32-, or 64-bit random number. """
166 return g_oMyRand.getrandbits(cBits);
167
168def randSxx(cBits):
169 """ Signed 8-, 16-, 32-, or 64-bit random number. """
170 uVal = randUxx(cBits);
171 iRet = uVal & ((1 << (cBits - 1)) - 1);
172 if iRet != uVal:
173 iRet = -iRet;
174 return iRet;
175
176def randUxxList(cBits, cElements):
177 """ List of unsigned 8-, 16-, 32-, or 64-bit random numbers. """
178 return [randUxx(cBits) for _ in range(cElements)];
179## @}
180
181
182
183
184## @name Instruction Emitter Helpers
185## @{
186
187def calcRexPrefixForTwoModRmRegs(iReg, iRm, bOtherRexPrefixes = 0):
188 """
189 Calculates a rex prefix if neccessary given the two registers
190 and optional rex size prefixes.
191 Returns an empty array if not necessary.
192 """
193 bRex = bOtherRexPrefixes;
194 if iReg >= 8:
195 bRex |= X86_OP_REX_R;
196 if iRm >= 8:
197 bRex |= X86_OP_REX_B;
198 if bRex == 0:
199 return [];
200 return [bRex,];
201
202def calcModRmForTwoRegs(iReg, iRm):
203 """
204 Calculate the RM byte for two registers.
205 Returns an array with one byte in it.
206 """
207 bRm = (0x3 << X86_MODRM_MOD_SHIFT) \
208 | ((iReg << X86_MODRM_REG_SHIFT) & X86_MODRM_REG_MASK) \
209 | (iRm & X86_MODRM_RM_MASK);
210 return [bRm,];
211
212## @}
213
214
215## @name Misc
216## @{
217
218def convU32ToSigned(u32):
219 """ Converts a 32-bit unsigned value to 32-bit signed. """
220 if u32 < 0x80000000:
221 return u32;
222 return u32 - UINT32_MAX - 1;
223
224def rotateLeftUxx(cBits, uVal, cShift):
225 """ Rotate a xx-bit wide unsigned number to the left. """
226 assert cShift < cBits;
227
228 if cBits == 16:
229 uMask = UINT16_MAX;
230 elif cBits == 32:
231 uMask = UINT32_MAX;
232 elif cBits == 64:
233 uMask = UINT64_MAX;
234 else:
235 assert cBits == 8;
236 uMask = UINT8_MAX;
237
238 uVal &= uMask;
239 uRet = (uVal << cShift) & uMask;
240 uRet |= (uVal >> (cBits - cShift));
241 return uRet;
242
243def rotateRightUxx(cBits, uVal, cShift):
244 """ Rotate a xx-bit wide unsigned number to the right. """
245 assert cShift < cBits;
246
247 if cBits == 16:
248 uMask = UINT16_MAX;
249 elif cBits == 32:
250 uMask = UINT32_MAX;
251 elif cBits == 64:
252 uMask = UINT64_MAX;
253 else:
254 assert cBits == 8;
255 uMask = UINT8_MAX;
256
257 uVal &= uMask;
258 uRet = (uVal >> cShift);
259 uRet |= (uVal << (cBits - cShift)) & uMask;
260 return uRet;
261
262def gregName(iReg, cBits, fRexByteRegs = True):
263 """ Gets the name of a general register by index and width. """
264 if cBits == 64:
265 return g_asGRegs64[iReg];
266 if cBits == 32:
267 return g_asGRegs32[iReg];
268 if cBits == 16:
269 return g_asGRegs16[iReg];
270 assert cBits == 8;
271 if fRexByteRegs:
272 return g_asGRegs8Rex[iReg];
273 return g_asGRegs8[iReg];
274
275## @}
276
277
278class TargetEnv(object):
279 """
280 Target Runtime Environment.
281 """
282
283 ## @name CPU Modes
284 ## @{
285 ksCpuMode_Real = 'real';
286 ksCpuMode_Protect = 'prot';
287 ksCpuMode_Paged = 'paged';
288 ksCpuMode_Long = 'long';
289 ksCpuMode_V86 = 'v86';
290 ## @}
291
292 ## @name Instruction set.
293 ## @{
294 ksInstrSet_16 = '16';
295 ksInstrSet_32 = '32';
296 ksInstrSet_64 = '64';
297 ## @}
298
299 def __init__(self, sName,
300 sInstrSet = ksInstrSet_32,
301 sCpuMode = ksCpuMode_Paged,
302 iRing = 3,
303 ):
304 self.sName = sName;
305 self.sInstrSet = sInstrSet;
306 self.sCpuMode = sCpuMode;
307 self.iRing = iRing;
308 self.asGRegs = g_asGRegs64 if self.is64Bit() else g_asGRegs32;
309 self.asGRegsNoSp = g_asGRegs64NoSp if self.is64Bit() else g_asGRegs32NoSp;
310
311 def isUsingIprt(self):
312 """ Whether it's an IPRT environment or not. """
313 return self.sName.startswith('iprt');
314
315 def is64Bit(self):
316 """ Whether it's a 64-bit environment or not. """
317 return self.sInstrSet == self.ksInstrSet_64;
318
319 def getDefOpBits(self):
320 """ Get the default operand size as a bit count. """
321 if self.sInstrSet == self.ksInstrSet_16:
322 return 16;
323 return 32;
324
325 def getDefOpBytes(self):
326 """ Get the default operand size as a byte count. """
327 return self.getDefOpBits() / 8;
328
329 def getMaxOpBits(self):
330 """ Get the max operand size as a bit count. """
331 if self.sInstrSet == self.ksInstrSet_64:
332 return 64;
333 return 32;
334
335 def getMaxOpBytes(self):
336 """ Get the max operand size as a byte count. """
337 return self.getMaxOpBits() / 8;
338
339 def getDefAddrBits(self):
340 """ Get the default address size as a bit count. """
341 if self.sInstrSet == self.ksInstrSet_16:
342 return 16;
343 if self.sInstrSet == self.ksInstrSet_32:
344 return 32;
345 return 64;
346
347 def getDefAddrBytes(self):
348 """ Get the default address size as a byte count. """
349 return self.getDefAddrBits() / 8;
350
351 def getGRegCount(self, cbEffBytes = 4):
352 """ Get the number of general registers. """
353 if self.sInstrSet == self.ksInstrSet_64:
354 if cbEffBytes == 1:
355 return 16 + 4;
356 return 16;
357 return 8;
358
359 def randGRegNoSp(self, cbEffBytes = 4):
360 """ Returns a random general register number, excluding the SP register. """
361 iReg = randU16() % self.getGRegCount(cbEffBytes);
362 while iReg == X86_GREG_xSP:
363 iReg = randU16() % self.getGRegCount(cbEffBytes);
364 return iReg;
365
366 def randGRegNoSpList(self, cItems, cbEffBytes = 4):
367 """ List of randGRegNoSp values. """
368 aiRegs = [];
369 for _ in range(cItems):
370 aiRegs.append(self.randGRegNoSp(cbEffBytes));
371 return aiRegs;
372
373 def getAddrModes(self):
374 """ Gets a list of addressing mode (16, 32, or/and 64). """
375 if self.sInstrSet == self.ksInstrSet_16:
376 return [16, 32];
377 if self.sInstrSet == self.ksInstrSet_32:
378 return [32, 16];
379 return [64, 32];
380
381 def is8BitHighGReg(self, cbEffOp, iGReg):
382 """ Checks if the given register is a high 8-bit general register (AH, CH, DH or BH). """
383 assert cbEffOp in [1, 2, 4, 8];
384 if cbEffOp == 1:
385 if iGReg >= 16:
386 return True;
387 if iGReg >= 4 and not self.is64Bit():
388 return True;
389 return False;
390
391 def gregNameBits(self, iReg, cBits):
392 """ Gets the name of the given register for the specified width (bits). """
393 return gregName(iReg, cBits, self.is64Bit());
394
395 def gregNameBytes(self, iReg, cbWidth):
396 """ Gets the name of the given register for the specified with (in bytes). """
397 return gregName(iReg, cbWidth * 8, self.is64Bit());
398
399
400
401
402## Target environments.
403g_dTargetEnvs = {
404 'iprt-r3-32': TargetEnv('iprt-r3-32', TargetEnv.ksInstrSet_32, TargetEnv.ksCpuMode_Protect, 3),
405 'iprt-r3-64': TargetEnv('iprt-r3-64', TargetEnv.ksInstrSet_64, TargetEnv.ksCpuMode_Long, 3),
406 'bs2-r0-64': TargetEnv('bs2-r0-64', TargetEnv.ksInstrSet_64, TargetEnv.ksCpuMode_Long, 0),
407 'bs2-r0-64-big': TargetEnv('bs2-r0-64-big', TargetEnv.ksInstrSet_64, TargetEnv.ksCpuMode_Long, 0),
408 'bs2-r0-32-big': TargetEnv('bs2-r0-32-big', TargetEnv.ksInstrSet_32, TargetEnv.ksCpuMode_Protect, 0),
409};
410
411
412class InstrTestBase(object):
413 """
414 Base class for testing one instruction.
415 """
416
417 def __init__(self, sName, sInstr = None):
418 self.sName = sName;
419 self.sInstr = sInstr if sInstr else sName.split()[0];
420
421 def isApplicable(self, oGen):
422 """
423 Tests if the instruction test is applicable to the selected environment.
424 """
425 _ = oGen;
426 return True;
427
428 def generateTest(self, oGen, sTestFnName):
429 """
430 Emits the test assembly code.
431 """
432 oGen.write(';; @todo not implemented. This is for the linter: %s, %s\n' % (oGen, sTestFnName));
433 return True;
434
435 def generateInputs(self, cbEffOp, cbMaxOp, oGen, fLong = False):
436 """ Generate a list of inputs. """
437 if fLong:
438 #
439 # Try do extremes as well as different ranges of random numbers.
440 #
441 auRet = [0, 1, ];
442 if cbMaxOp >= 1:
443 auRet += [ UINT8_MAX / 2, UINT8_MAX / 2 + 1, UINT8_MAX ];
444 if cbMaxOp >= 2:
445 auRet += [ UINT16_MAX / 2, UINT16_MAX / 2 + 1, UINT16_MAX ];
446 if cbMaxOp >= 4:
447 auRet += [ UINT32_MAX / 2, UINT32_MAX / 2 + 1, UINT32_MAX ];
448 if cbMaxOp >= 8:
449 auRet += [ UINT64_MAX / 2, UINT64_MAX / 2 + 1, UINT64_MAX ];
450
451 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
452 for cBits, cValues in ( (8, 4), (16, 4), (32, 8), (64, 8) ):
453 if cBits < cbMaxOp * 8:
454 auRet += randUxxList(cBits, cValues);
455 cWanted = 16;
456 elif oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
457 for cBits, cValues in ( (8, 8), (16, 8), (24, 2), (32, 16), (40, 1), (48, 1), (56, 1), (64, 16) ):
458 if cBits < cbMaxOp * 8:
459 auRet += randUxxList(cBits, cValues);
460 cWanted = 64;
461 else:
462 for cBits, cValues in ( (8, 16), (16, 16), (24, 4), (32, 64), (40, 4), (48, 4), (56, 4), (64, 64) ):
463 if cBits < cbMaxOp * 8:
464 auRet += randUxxList(cBits, cValues);
465 cWanted = 168;
466 if len(auRet) < cWanted:
467 auRet += randUxxList(cbEffOp * 8, cWanted - len(auRet));
468 else:
469 #
470 # Short list, just do some random numbers.
471 #
472 auRet = [];
473 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
474 auRet += randUxxList(cbMaxOp, 1);
475 elif oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
476 auRet += randUxxList(cbMaxOp, 2);
477 else:
478 auRet = [];
479 for cBits in (8, 16, 32, 64):
480 if cBits < cbMaxOp * 8:
481 auRet += randUxxList(cBits, 1);
482 return auRet;
483
484
485class InstrTest_MemOrGreg_2_Greg(InstrTestBase):
486 """
487 Instruction reading memory or general register and writing the result to a
488 general register.
489 """
490
491 def __init__(self, sName, fnCalcResult, sInstr = None, acbOpVars = None):
492 InstrTestBase.__init__(self, sName, sInstr);
493 self.fnCalcResult = fnCalcResult;
494 self.acbOpVars = [ 1, 2, 4, 8 ] if not acbOpVars else list(acbOpVars);
495 self.fTestRegForm = True;
496 self.fTestMemForm = True;
497
498 ## @name Test Instruction Writers
499 ## @{
500
501 def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
502 """ Writes the instruction with two general registers as operands. """
503 oGen.write(' %s %s, %s\n'
504 % ( self.sInstr, oGen.gregNameBytes(iOp1, cbEffOp), oGen.gregNameBytes(iOp2, cbEffOp),));
505 return True;
506
507 def writeInstrGregPureRM(self, cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen):
508 """ Writes the instruction with two general registers as operands. """
509 oGen.write(' ');
510 if iOp2 == 13 and iMod == 0 and cAddrBits == 64:
511 oGen.write('altrexb '); # Alternative encoding for rip relative addressing.
512 oGen.write('%s %s, [' % (self.sInstr, oGen.gregNameBytes(iOp1, cbEffOp),));
513 if (iOp2 == 5 or iOp2 == 13) and iMod == 0:
514 oGen.write('VBINSTST_NAME(g_u%sData)' % (cbEffOp * 8,))
515 if oGen.oTarget.is64Bit():
516 oGen.write(' wrt rip');
517 else:
518 if iMod == 1:
519 oGen.write('byte %d + ' % (offDisp,));
520 elif iMod == 2:
521 oGen.write('dword %d + ' % (offDisp,));
522 else:
523 assert iMod == 0;
524
525 if cAddrBits == 64:
526 oGen.write(g_asGRegs64[iOp2]);
527 elif cAddrBits == 32:
528 oGen.write(g_asGRegs32[iOp2]);
529 elif cAddrBits == 16:
530 assert False; ## @todo implement 16-bit addressing.
531 else:
532 assert False, str(cAddrBits);
533
534 oGen.write(']\n');
535 return True;
536
537 def writeInstrGregSibLabel(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
538 """ Writes the instruction taking a register and a label (base only w/o reg), SIB form. """
539 assert offDisp is None; assert iBaseReg in [5, 13]; assert iIndexReg == 4; assert cAddrBits != 16;
540 if cAddrBits == 64:
541 # Note! Cannot test this in 64-bit mode in any sensible way because the disp is 32-bit
542 # and we cannot (yet) make assumtions about where we're loaded.
543 ## @todo Enable testing this in environments where we can make assumptions (boot sector).
544 oGen.write(' %s %s, [VBINSTST_NAME(g_u%sData) xWrtRIP]\n'
545 % ( self.sInstr, oGen.gregNameBytes(iOp1, cbEffOp), cbEffOp * 8,));
546 else:
547 oGen.write(' altsibx%u %s %s, [VBINSTST_NAME(g_u%sData) xWrtRIP] ; iOp1=%s cbEffOp=%s\n'
548 % ( iScale, self.sInstr, oGen.gregNameBytes(iOp1, cbEffOp), cbEffOp * 8, iOp1, cbEffOp));
549 return True;
550
551 def writeInstrGregSibScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
552 """ Writes the instruction taking a register and disp+scaled register (no base reg), SIB form. """
553 assert iBaseReg in [5, 13]; assert iIndexReg != 4; assert cAddrBits != 16;
554 # Note! Using altsibxN to force scaled encoding. This is only really a
555 # necessity for iScale=1, but doesn't hurt for the rest.
556 oGen.write(' altsibx%u %s %s, [%s * %#x'
557 % (iScale, self.sInstr, oGen.gregNameBytes(iOp1, cbEffOp), oGen.gregNameBits(iIndexReg, cAddrBits), iScale,));
558 if offDisp is not None:
559 oGen.write(' + %#x' % (offDisp,));
560 oGen.write(']\n');
561 _ = iBaseReg;
562 return True;
563
564 def writeInstrGregSibBase(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
565 """ Writes the instruction taking a register and base only (with reg), SIB form. """
566 oGen.write(' altsibx%u %s %s, [%s'
567 % (iScale, self.sInstr, oGen.gregNameBytes(iOp1, cbEffOp), oGen.gregNameBits(iBaseReg, cAddrBits),));
568 if offDisp is not None:
569 oGen.write(' + %#x' % (offDisp,));
570 oGen.write(']\n');
571 _ = iIndexReg;
572 return True;
573
574 def writeInstrGregSibBaseAndScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
575 """ Writes tinstruction taking a register and full featured SIB form address. """
576 # Note! From the looks of things, yasm will encode the following instructions the same way:
577 # mov eax, [rsi*1 + rbx]
578 # mov eax, [rbx + rsi*1]
579 # So, when there are two registers involved, the '*1' selects
580 # which is index and which is base.
581 oGen.write(' %s %s, [%s + %s * %u'
582 % ( self.sInstr, oGen.gregNameBytes(iOp1, cbEffOp),
583 oGen.gregNameBits(iBaseReg, cAddrBits), oGen.gregNameBits(iIndexReg, cAddrBits), iScale,));
584 if offDisp is not None:
585 oGen.write(' + %#x' % (offDisp,));
586 oGen.write(']\n');
587 return True;
588
589 ## @}
590
591
592 ## @name Memory setups
593 ## @{
594
595 def generateMemSetupReadByLabel(self, oGen, cbEffOp, uInput):
596 """ Sets up memory for a memory read. """
597 oGen.pushConst(uInput);
598 oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
599 return True;
600
601 def generateMemSetupReadByReg(self, oGen, cAddrBits, cbEffOp, iReg1, uInput, offDisp = None):
602 """ Sets up memory for a memory read indirectly addressed thru one register and optional displacement. """
603 oGen.pushConst(uInput);
604 oGen.write(' call VBINSTST_NAME(%s)\n'
605 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iBaseReg = iReg1, offDisp = offDisp),));
606 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iReg1],));
607 return True;
608
609 def generateMemSetupReadByScaledReg(self, oGen, cAddrBits, cbEffOp, iIndexReg, iScale, uInput, offDisp = None):
610 """ Sets up memory for a memory read indirectly addressed thru one register and optional displacement. """
611 oGen.pushConst(uInput);
612 oGen.write(' call VBINSTST_NAME(%s)\n'
613 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, offDisp = offDisp, iIndexReg = iIndexReg, iScale = iScale),));
614 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iIndexReg],));
615 return True;
616
617 def generateMemSetupReadByBaseAndScaledReg(self, oGen, cAddrBits, cbEffOp, iBaseReg, iIndexReg, iScale, uInput, offDisp):
618 """ Sets up memory for a memory read indirectly addressed thru two registers with optional displacement. """
619 oGen.pushConst(uInput);
620 oGen.write(' call VBINSTST_NAME(%s)\n'
621 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iBaseReg = iBaseReg, offDisp = offDisp,
622 iIndexReg = iIndexReg, iScale = iScale),));
623 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iIndexReg],));
624 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iBaseReg],));
625 return True;
626
627 def generateMemSetupPureRM(self, oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp = None):
628 """ Sets up memory for a pure R/M addressed read, iOp2 being the R/M value. """
629 oGen.pushConst(uInput);
630 assert offDisp is None or iMod != 0;
631 if (iOp2 != 5 and iOp2 != 13) or iMod != 0:
632 oGen.write(' call VBINSTST_NAME(%s)\n'
633 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iOp2, offDisp),));
634 else:
635 oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
636 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
637 return True;
638
639 ## @}
640
641 def generateOneStdTestGregGreg(self, oGen, cbEffOp, cbMaxOp, iOp1, iOp1X, iOp2, iOp2X, uInput, uResult):
642 """ Generate one standard instr greg,greg test. """
643 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
644 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uInput,));
645 if iOp1X != iOp2X:
646 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
647 self.writeInstrGregGreg(cbEffOp, iOp1, iOp2, oGen);
648 oGen.pushConst(uResult);
649 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1X, iOp2X if iOp1X != iOp2X else None),));
650 _ = cbMaxOp;
651 return True;
652
653 def generateOneStdTestGregGreg8BitHighPain(self, oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput):
654 """ High 8-bit registers are a real pain! """
655 assert oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) or oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2);
656 # Figure out the register indexes of the max op sized regs involved.
657 iOp1X = iOp1 & 3;
658 iOp2X = iOp2 & 3;
659 oGen.write(' ; iOp1=%u iOp1X=%u iOp2=%u iOp2X=%u\n' % (iOp1, iOp1X, iOp2, iOp2X,));
660
661 # Calculate unshifted result.
662 if iOp1X != iOp2X:
663 uCur = oGen.auRegValues[iOp1X];
664 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1):
665 uCur = rotateRightUxx(cbMaxOp * 8, uCur, 8);
666 else:
667 uCur = uInput;
668 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) != oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
669 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1):
670 uCur = rotateRightUxx(cbMaxOp * 8, uCur, 8);
671 else:
672 uCur = rotateLeftUxx(cbMaxOp * 8, uCur, 8);
673 uResult = self.fnCalcResult(cbEffOp, uInput, uCur, oGen);
674
675
676 # Rotate the input and/or result to match their max-op-sized registers.
677 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
678 uInput = rotateLeftUxx(cbMaxOp * 8, uInput, 8);
679 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1):
680 uResult = rotateLeftUxx(cbMaxOp * 8, uResult, 8);
681
682 # Hand it over to an overridable worker method.
683 return self.generateOneStdTestGregGreg(oGen, cbEffOp, cbMaxOp, iOp1, iOp1X, iOp2, iOp2X, uInput, uResult);
684
685
686 def generateOneStdTestGregMemNoSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iOp2, uInput, uResult):
687 """ Generate mode 0, 1 and 2 test for the R/M=iOp2. """
688 if cAddrBits == 16:
689 _ = cbMaxOp;
690 else:
691 iMod = 0; # No disp, except for i=5.
692 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
693 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput);
694 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, None, oGen);
695 oGen.pushConst(uResult);
696 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
697
698 if iOp2 != 5 and iOp2 != 13:
699 iMod = 1;
700 for offDisp in oGen.getDispForMod(iMod):
701 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
702 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp);
703 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen);
704 oGen.pushConst(uResult);
705 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
706
707 iMod = 2;
708 for offDisp in oGen.getDispForMod(iMod):
709 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
710 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp);
711 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen);
712 oGen.pushConst(uResult);
713 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
714
715 return True;
716
717 def generateOneStdTestGregMemSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod, # pylint: disable=R0913
718 iBaseReg, iIndexReg, iScale, uInput, uResult):
719 """ Generate one SIB variations. """
720 for offDisp in oGen.getDispForMod(iMod, cbEffOp):
721 if ((iBaseReg == 5 or iBaseReg == 13) and iMod == 0):
722 if iIndexReg == 4:
723 if cAddrBits == 64:
724 continue; # skipping.
725 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
726 self.generateMemSetupReadByLabel(oGen, cbEffOp, uInput);
727 self.writeInstrGregSibLabel(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
728 sChecker = oGen.needGRegChecker(iOp1);
729 else:
730 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
731 self.generateMemSetupReadByScaledReg(oGen, cAddrBits, cbEffOp, iIndexReg, iScale, uInput, offDisp);
732 self.writeInstrGregSibScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
733 sChecker = oGen.needGRegChecker(iOp1, iIndexReg);
734 else:
735 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
736 if iIndexReg == 4:
737 self.generateMemSetupReadByReg(oGen, cAddrBits, cbEffOp, iBaseReg, uInput, offDisp);
738 self.writeInstrGregSibBase(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
739 sChecker = oGen.needGRegChecker(iOp1, iBaseReg);
740 else:
741 if iIndexReg == iBaseReg and iScale == 1 and offDisp is not None and (offDisp & 1):
742 if offDisp < 0: offDisp += 1;
743 else: offDisp -= 1;
744 self.generateMemSetupReadByBaseAndScaledReg(oGen, cAddrBits, cbEffOp, iBaseReg,
745 iIndexReg, iScale, uInput, offDisp);
746 self.writeInstrGregSibBaseAndScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
747 sChecker = oGen.needGRegChecker(iOp1, iBaseReg, iIndexReg);
748 oGen.pushConst(uResult);
749 oGen.write(' call VBINSTST_NAME(%s)\n' % (sChecker,));
750 _ = cbMaxOp;
751 return True;
752
753 def generateStdTestGregMemSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, auInputs):
754 """ Generate all SIB variations for the given iOp1 (reg) value. """
755 assert cAddrBits in [32, 64];
756 i = oGen.cSibBasePerRun;
757 while i > 0:
758 oGen.iSibBaseReg = (oGen.iSibBaseReg + 1) % oGen.oTarget.getGRegCount(cAddrBits / 8);
759 if oGen.iSibBaseReg == X86_GREG_xSP: # no RSP testing atm.
760 continue;
761
762 j = oGen.getSibIndexPerRun();
763 while j > 0:
764 oGen.iSibIndexReg = (oGen.iSibIndexReg + 1) % oGen.oTarget.getGRegCount(cAddrBits / 8);
765 if oGen.iSibIndexReg == iOp1 and oGen.iSibIndexReg != 4 and cAddrBits != cbMaxOp:
766 continue; # Don't know the high bit of the address ending up the result - skip it for now.
767
768 for iMod in [0, 1, 2]:
769 if oGen.iSibBaseReg == iOp1 \
770 and ((oGen.iSibBaseReg != 5 and oGen.iSibBaseReg != 13) or iMod != 0) \
771 and cAddrBits != cbMaxOp:
772 continue; # Don't know the high bit of the address ending up the result - skip it for now.
773
774 for _ in oGen.oSibScaleRange:
775 oGen.iSibScale *= 2;
776 if oGen.iSibScale > 8:
777 oGen.iSibScale = 1;
778
779 for uInput in auInputs:
780 oGen.newSubTest();
781 uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[iOp1], oGen);
782 self.generateOneStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod,
783 oGen.iSibBaseReg, oGen.iSibIndexReg, oGen.iSibScale,
784 uInput, uResult);
785 j -= 1;
786 i -= 1;
787
788 return True;
789
790
791 def generateStandardTests(self, oGen):
792 """ Generate standard tests. """
793
794 # Parameters.
795 cbDefOp = oGen.oTarget.getDefOpBytes();
796 cbMaxOp = oGen.oTarget.getMaxOpBytes();
797 auShortInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen);
798 auLongInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen, fLong = True);
799 iLongOp1 = oGen.oTarget.randGRegNoSp();
800 iLongOp2 = oGen.oTarget.randGRegNoSp();
801
802 # Register tests
803 if self.fTestRegForm:
804 for cbEffOp in self.acbOpVars:
805 if cbEffOp > cbMaxOp:
806 continue;
807 oOp2Range = range(oGen.oTarget.getGRegCount(cbEffOp));
808 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
809 oOp2Range = [iLongOp2,];
810 oGen.write('; cbEffOp=%u\n' % (cbEffOp,));
811
812 for iOp1 in range(oGen.oTarget.getGRegCount(cbEffOp)):
813 if iOp1 == X86_GREG_xSP:
814 continue; # Cannot test xSP atm.
815 for iOp2 in oOp2Range:
816 if (iOp2 >= 16 and iOp1 in range(4, 16)) \
817 or (iOp1 >= 16 and iOp2 in range(4, 16)):
818 continue; # Any REX encoding turns AH,CH,DH,BH regs into SPL,BPL,SIL,DIL.
819 if iOp2 == X86_GREG_xSP:
820 continue; # Cannot test xSP atm.
821
822 oGen.write('; iOp2=%u cbEffOp=%u\n' % (iOp2, cbEffOp));
823 for uInput in (auLongInputs if iOp1 == iLongOp1 and iOp2 == iLongOp2 else auShortInputs):
824 oGen.newSubTest();
825 if not oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) and not oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
826 uCur = oGen.auRegValues[iOp1 & 15] if iOp1 != iOp2 else uInput;
827 uResult = self.fnCalcResult(cbEffOp, uInput, uCur, oGen);
828 self.generateOneStdTestGregGreg(oGen, cbEffOp, cbMaxOp, iOp1, iOp1 & 15, iOp2, iOp2 & 15,
829 uInput, uResult);
830 else:
831 self.generateOneStdTestGregGreg8BitHighPain(oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput);
832
833 # Memory test.
834 if self.fTestMemForm:
835 for cAddrBits in oGen.oTarget.getAddrModes():
836 for cbEffOp in self.acbOpVars:
837 if cbEffOp > cbMaxOp:
838 continue;
839
840 for _ in oGen.getModRegRange(cbEffOp):
841 oGen.iModReg = (oGen.iModReg + 1) % oGen.oTarget.getGRegCount(cbEffOp);
842 if oGen.iModReg == X86_GREG_xSP:
843 continue; # Cannot test xSP atm.
844 if oGen.iModReg > 15:
845 continue; ## TODO AH,CH,DH,BH
846
847 auInputs = auLongInputs if oGen.iModReg == iLongOp1 else auShortInputs;
848 for _ in oGen.oModRmRange:
849 oGen.iModRm = (oGen.iModRm + 1) % oGen.oTarget.getGRegCount(cAddrBits * 8);
850 if oGen.iModRm != 4 or cAddrBits == 16:
851 for uInput in auInputs:
852 oGen.newSubTest();
853 if oGen.iModReg == oGen.iModRm and oGen.iModRm != 5 \
854 and oGen.iModRm != 13 and cbEffOp != cbMaxOp:
855 continue; # Don't know the high bit of the address ending up the result - skip it for now.
856 uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[oGen.iModReg & 15], oGen);
857 self.generateOneStdTestGregMemNoSib(oGen, cAddrBits, cbEffOp, cbMaxOp,
858 oGen.iModReg, oGen.iModRm, uInput, uResult);
859 else:
860 # SIB - currently only short list of inputs or things may get seriously out of hand.
861 self.generateStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, oGen.iModReg, auShortInputs);
862 return True;
863
864 def generateTest(self, oGen, sTestFnName):
865 oGen.write('VBINSTST_BEGINPROC %s\n' % (sTestFnName,));
866
867 self.generateStandardTests(oGen);
868
869 oGen.write(' ret\n');
870 oGen.write('VBINSTST_ENDPROC %s\n' % (sTestFnName,));
871 return True;
872
873
874
875class InstrTest_Mov_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
876 """
877 Tests MOV Gv,Ev.
878 """
879 def __init__(self):
880 InstrTest_MemOrGreg_2_Greg.__init__(self, 'mov Gv,Ev', self.calc_mov);
881
882 @staticmethod
883 def calc_mov(cbEffOp, uInput, uCur, oGen):
884 """ Calculates the result of a mov instruction."""
885 if cbEffOp == 8:
886 return uInput & UINT64_MAX;
887 if cbEffOp == 4:
888 return uInput & UINT32_MAX;
889 if cbEffOp == 2:
890 return (uCur & 0xffffffffffff0000) | (uInput & UINT16_MAX);
891 assert cbEffOp == 1; _ = oGen;
892 return (uCur & 0xffffffffffffff00) | (uInput & UINT8_MAX);
893
894
895class InstrTest_MovSxD_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
896 """
897 Tests MOVSXD Gv,Ev.
898 """
899 def __init__(self):
900 InstrTest_MemOrGreg_2_Greg.__init__(self, 'movsxd Gv,Ev', self.calc_movsxd, acbOpVars = [ 8, 4, 2, ]);
901 self.fTestMemForm = False; # drop this...
902
903 def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
904 """ Writes the instruction with two general registers as operands. """
905 if cbEffOp == 8:
906 oGen.write(' movsxd %s, %s\n'
907 % ( oGen.gregNameBytes(iOp1, cbEffOp), oGen.gregNameBytes(iOp2, cbEffOp / 2),));
908 else:
909 oGen.write(' oddmovsxd %s, %s\n'
910 % ( oGen.gregNameBytes(iOp1, cbEffOp), oGen.gregNameBytes(iOp2, cbEffOp),));
911 return True;
912
913 def isApplicable(self, oGen):
914 return oGen.oTarget.is64Bit();
915
916 @staticmethod
917 def calc_movsxd(cbEffOp, uInput, uCur, oGen):
918 """
919 Calculates the result of a movxsd instruction.
920 Returns the result value (cbMaxOp sized).
921 """
922 _ = oGen;
923 if cbEffOp == 8 and (uInput & RT_BIT_32(31)):
924 return (UINT32_MAX << 32) | (uInput & UINT32_MAX);
925 if cbEffOp == 2:
926 return (uCur & 0xffffffffffff0000) | (uInput & 0xffff);
927 return uInput & UINT32_MAX;
928
929
930class InstrTest_DivIDiv(InstrTestBase):
931 """
932 Tests IDIV and DIV instructions.
933 """
934
935 def __init__(self, fIsIDiv):
936 if not fIsIDiv:
937 InstrTestBase.__init__(self, 'div Gv,Ev', 'div');
938 else:
939 InstrTestBase.__init__(self, 'idiv Gv,Ev', 'idiv');
940 self.fIsIDiv = fIsIDiv;
941
942 def generateInputEdgeCases(self, cbEffOp, fLong, fXcpt):
943 """ Generate edge case inputs for cbEffOp. Returns a list of pairs, dividen + divisor. """
944 # Test params.
945 uStep = 1 << (cbEffOp * 8);
946 if self.fIsIDiv:
947 uStep /= 2;
948
949 # edge tests
950 auRet = [];
951
952 uDivisor = 1 if fLong else 3;
953 uDividend = uStep * uDivisor - 1;
954 for i in range(5 if fLong else 3):
955 auRet.append([uDividend + fXcpt, uDivisor]);
956 if self.fIsIDiv:
957 auRet.append([-uDividend - fXcpt, -uDivisor]);
958 auRet.append([-(uDividend + uDivisor + fXcpt), uDivisor]);
959 auRet.append([ (uDividend + uDivisor + fXcpt), -uDivisor]);
960 if i <= 3 and fLong:
961 auRet.append([uDividend - 1 + fXcpt*3, uDivisor]);
962 if self.fIsIDiv:
963 auRet.append([-(uDividend - 1 + fXcpt*3), -uDivisor]);
964 uDivisor += 1;
965 uDividend += uStep;
966
967 uDivisor = uStep - 1;
968 uDividend = uStep * uDivisor - 1;
969 for _ in range(3 if fLong else 1):
970 auRet.append([uDividend + fXcpt, uDivisor]);
971 if self.fIsIDiv:
972 auRet.append([-uDividend - fXcpt, -uDivisor]);
973 uDivisor -= 1;
974 uDividend -= uStep;
975
976 if self.fIsIDiv:
977 uDivisor = -uStep;
978 for _ in range(3 if fLong else 1):
979 auRet.append([uDivisor * (-uStep - 1) - (not fXcpt), uDivisor]);
980 uDivisor += 1
981 uDivisor = uStep - 1;
982 for _ in range(3 if fLong else 1):
983 auRet.append([-(uDivisor * (uStep + 1) - (not fXcpt)), uDivisor]);
984 uDivisor -= 1
985
986 return auRet;
987
988 def generateInputsNoXcpt(self, cbEffOp, fLong = False):
989 """ Generate inputs for cbEffOp. Returns a list of pairs, dividen + divisor. """
990 # Test params.
991 uStep = 1 << (cbEffOp * 8);
992 if self.fIsIDiv:
993 uStep /= 2;
994
995 # edge tests
996 auRet = self.generateInputEdgeCases(cbEffOp, fLong, False)
997
998 # random tests.
999 if self.fIsIDiv:
1000 for _ in range(6 if fLong else 2):
1001 while True:
1002 uDivisor = randSxx(cbEffOp * 8);
1003 if uDivisor == 0 or uDivisor >= uStep or uDivisor < -uStep:
1004 continue;
1005 uDividend = randSxx(cbEffOp * 16);
1006 uResult = uDividend / uDivisor;
1007 if uResult >= uStep or uResult <= -uStep: # exclude difficulties
1008 continue;
1009 break;
1010 auRet.append([uDividend, uDivisor]);
1011 else:
1012 for _ in range(6 if fLong else 2):
1013 while True:
1014 uDivisor = randUxx(cbEffOp * 8);
1015 if uDivisor == 0 or uDivisor >= uStep:
1016 continue;
1017 uDividend = randUxx(cbEffOp * 16);
1018 uResult = uDividend / uDivisor;
1019 if uResult >= uStep:
1020 continue;
1021 break;
1022 auRet.append([uDividend, uDivisor]);
1023
1024 return auRet;
1025
1026 def generateOneStdTestGreg(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1027 """ Generate code of one '[I]DIV rDX:rAX,<GREG>' test. """
1028 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1029 fEffOp = ((1 << (cbEffOp *8) ) - 1);
1030 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1031 fTopOp = fMaxOp - fEffOp;
1032 fFullOp1 = ((1 << (cbEffOp*16)) - 1);
1033
1034 uAX = iDividend & fFullOp1; # full with unsigned
1035 uDX = uAX >> (cbEffOp*8);
1036 uAX &= fEffOp;
1037 uOp2Val = iDivisor & fEffOp;
1038
1039 iQuotient = iDividend / iDivisor;
1040 iReminder = iDividend % iDivisor;
1041 if iReminder != 0 and iQuotient < 0: # python has different rounding rules for negative division.
1042 iQuotient += 1;
1043 iReminder -= iDivisor;
1044 uAXResult = iQuotient & fEffOp;
1045 uDXResult = iReminder & fEffOp;
1046
1047 if cbEffOp < cbMaxOp:
1048 uAX |= randUxx(cbMaxOp * 8) & fTopOp;
1049 uDX |= randUxx(cbMaxOp * 8) & fTopOp;
1050 uOp2Val |= randUxx(cbMaxOp * 8) & fTopOp;
1051 if cbEffOp < 4:
1052 uAXResult |= uAX & fTopOp;
1053 uDXResult |= uDX & fTopOp;
1054 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1055 ' ; iQuotient=%#x (%d) iReminder=%#x (%d)\n'
1056 % ( iDividend & fFullOp1, iDividend, iDivisor & fEffOp, iDivisor,
1057 iQuotient & fEffOp, iQuotient, iReminder & fEffOp, iReminder, ));
1058
1059 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1060 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xDX], uDX,));
1061 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1062 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2], uOp2Val,));
1063
1064 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
1065 oGen.pushConst(uDXResult);
1066 oGen.pushConst(uAXResult);
1067
1068 oGen.write(' %-4s %s\n' % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1069 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, X86_GREG_xDX, iOp2),));
1070 return True;
1071
1072 def generateOneStdTestGreg8Bit(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1073 """ Generate code of one '[I]DIV AX,<GREG>' test (8-bit). """
1074 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1075 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1076 iOp2X = (iOp2 & 3) if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2) else iOp2;
1077 assert iOp2X != X86_GREG_xAX;
1078
1079 uAX = iDividend & UINT16_MAX; # full with unsigned
1080 uOp2Val = iDivisor & UINT8_MAX;
1081
1082 iQuotient = iDividend / iDivisor;
1083 iReminder = iDividend % iDivisor;
1084 if iReminder != 0 and iQuotient < 0: # python has different rounding rules for negative division.
1085 iQuotient += 1;
1086 iReminder -= iDivisor;
1087 uAXResult = (iQuotient & UINT8_MAX) | ((iReminder & UINT8_MAX) << 8);
1088
1089 uAX |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT16_MAX);
1090 uAXResult |= uAX & (fMaxOp - UINT16_MAX);
1091 uOp2Val |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT8_MAX);
1092 if iOp2X != iOp2:
1093 uOp2Val = rotateLeftUxx(cbMaxOp * 8, uOp2Val, 8);
1094 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1095 ' ; iQuotient=%#x (%d) iReminder=%#x (%d)\n'
1096 % ( iDividend & UINT16_MAX, iDividend, iDivisor & UINT8_MAX, iDivisor,
1097 iQuotient & UINT8_MAX, iQuotient, iReminder & UINT8_MAX, iReminder, ));
1098
1099 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1100 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1101 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uOp2Val,));
1102 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
1103 oGen.pushConst(uAXResult);
1104
1105 oGen.write(' %-4s %s\n' % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1106 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, iOp2X),));
1107 return;
1108
1109
1110 def generateStandardTests(self, oGen):
1111 """ Generates test that causes no exceptions. """
1112
1113 # Parameters.
1114 iLongOp2 = oGen.oTarget.randGRegNoSp();
1115
1116 # Register tests
1117 if True:
1118 for cbEffOp in ( 8, 4, 2, 1 ):
1119 if cbEffOp > oGen.oTarget.getMaxOpBytes():
1120 continue;
1121 oGen.write('; cbEffOp=%u\n' % (cbEffOp,));
1122 oOp2Range = range(oGen.oTarget.getGRegCount(cbEffOp));
1123 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
1124 oOp2Range = [iLongOp2,];
1125 for iOp2 in oOp2Range:
1126 if iOp2 == X86_GREG_xSP:
1127 continue; # Cannot test xSP atm.
1128 if iOp2 == X86_GREG_xAX or (cbEffOp > 1 and iOp2 == X86_GREG_xDX):
1129 continue; # Will overflow or be too complicated to get right.
1130 if cbEffOp == 1 and iOp2 == (16 if oGen.oTarget.is64Bit() else 4):
1131 continue; # Avoid dividing by AH, same reasons as above.
1132
1133 for iDividend, iDivisor in self.generateInputsNoXcpt(cbEffOp, iOp2 == iLongOp2):
1134 oGen.newSubTest();
1135 if cbEffOp > 1:
1136 self.generateOneStdTestGreg(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1137 else:
1138 self.generateOneStdTestGreg8Bit(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1139
1140 ## Memory test.
1141 #if False:
1142 # for cAddrBits in oGen.oTarget.getAddrModes():
1143 # for cbEffOp in self.acbOpVars:
1144 # if cbEffOp > cbMaxOp:
1145 # continue;
1146 #
1147 # auInputs = auLongInputs if oGen.iModReg == iLongOp1 else auShortInputs;
1148 # for _ in oGen.oModRmRange:
1149 # oGen.iModRm = (oGen.iModRm + 1) % oGen.oTarget.getGRegCount(cAddrBits * 8);
1150 # if oGen.iModRm != 4 or cAddrBits == 16:
1151 # for uInput in auInputs:
1152 # oGen.newSubTest();
1153 # if oGen.iModReg == oGen.iModRm and oGen.iModRm != 5 and oGen.iModRm != 13 and cbEffOp != cbMaxOp:
1154 # continue; # Don't know the high bit of the address ending up the result - skip it for now.
1155 # uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[oGen.iModReg & 15], oGen);
1156 # self.generateOneStdTestGregMemNoSib(oGen, cAddrBits, cbEffOp, cbMaxOp,
1157 # oGen.iModReg, oGen.iModRm, uInput, uResult);
1158 # else:
1159 # # SIB - currently only short list of inputs or things may get seriously out of hand.
1160 # self.generateStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, oGen.iModReg, auShortInputs);
1161 #
1162 return True;
1163
1164 def generateInputsXcpt(self, cbEffOp, fLong = False):
1165 """
1166 Generate inputs for cbEffOp that will overflow or underflow.
1167 Returns a list of pairs, dividen + divisor.
1168 """
1169 # Test params.
1170 uStep = 1 << (cbEffOp * 8);
1171 if self.fIsIDiv:
1172 uStep /= 2;
1173
1174 # edge tests
1175 auRet = self.generateInputEdgeCases(cbEffOp, fLong, True);
1176 auRet.extend([[0, 0], [1, 0], [ uStep * uStep / 2 - 1, 0]]);
1177
1178 # random tests.
1179 if self.fIsIDiv:
1180 for _ in range(6 if fLong else 2):
1181 while True:
1182 uDivisor = randSxx(cbEffOp * 8);
1183 uDividend = randSxx(cbEffOp * 16);
1184 if uDivisor >= uStep or uDivisor < -uStep:
1185 continue;
1186 if uDivisor != 0:
1187 uResult = uDividend / uDivisor;
1188 if (uResult <= uStep and uResult >= 0) or (uResult >= -uStep and uResult < 0):
1189 continue; # exclude difficulties
1190 break;
1191 auRet.append([uDividend, uDivisor]);
1192 else:
1193 for _ in range(6 if fLong else 2):
1194 while True:
1195 uDivisor = randUxx(cbEffOp * 8);
1196 uDividend = randUxx(cbEffOp * 16);
1197 if uDivisor >= uStep:
1198 continue;
1199 if uDivisor != 0:
1200 uResult = uDividend / uDivisor;
1201 if uResult < uStep:
1202 continue;
1203 break;
1204 auRet.append([uDividend, uDivisor]);
1205
1206 return auRet;
1207
1208 def generateOneDivideErrorTestGreg(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1209 """ Generate code of one '[I]DIV rDX:rAX,<GREG>' test that causes #DE. """
1210 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1211 fEffOp = ((1 << (cbEffOp *8) ) - 1);
1212 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1213 fTopOp = fMaxOp - fEffOp;
1214 fFullOp1 = ((1 << (cbEffOp*16)) - 1);
1215
1216 uAX = iDividend & fFullOp1; # full with unsigned
1217 uDX = uAX >> (cbEffOp*8);
1218 uAX &= fEffOp;
1219 uOp2Val = iDivisor & fEffOp;
1220
1221 if cbEffOp < cbMaxOp:
1222 uAX |= randUxx(cbMaxOp * 8) & fTopOp;
1223 uDX |= randUxx(cbMaxOp * 8) & fTopOp;
1224 uOp2Val |= randUxx(cbMaxOp * 8) & fTopOp;
1225 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1226 % ( iDividend & fFullOp1, iDividend, iDivisor & fEffOp, iDivisor,));
1227 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1228 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xDX], uDX,));
1229 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1230 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2], uOp2Val,));
1231 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
1232 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[X86_GREG_xDX],));
1233 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX],));
1234 oGen.write(' VBINSTST_TRAP_INSTR X86_XCPT_DE, 0, %-4s %s\n'
1235 % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1236 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, X86_GREG_xDX, iOp2),));
1237 return True;
1238
1239 def generateOneDivideErrorTestGreg8Bit(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1240 """ Generate code of one '[I]DIV AX,<GREG>' test that causes #DE (8-bit). """
1241 if not oGen.oTarget.is64Bit() and iOp2 == 4: # Avoid AH.
1242 iOp2 = 5;
1243
1244 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1245 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1246 iOp2X = (iOp2 & 3) if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2) else iOp2;
1247 assert iOp2X != X86_GREG_xAX;
1248
1249 uAX = iDividend & UINT16_MAX; # full with unsigned
1250 uOp2Val = iDivisor & UINT8_MAX;
1251
1252 uAX |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT16_MAX);
1253 uOp2Val |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT8_MAX);
1254 if iOp2X != iOp2:
1255 uOp2Val = rotateLeftUxx(cbMaxOp * 8, uOp2Val, 8);
1256 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1257 % ( iDividend & UINT16_MAX, iDividend, iDivisor & UINT8_MAX, iDivisor,));
1258 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1259 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1260 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uOp2Val,));
1261 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
1262 oGen.write(' push sAX\n');
1263 oGen.write(' VBINSTST_TRAP_INSTR X86_XCPT_DE, 0, %-4s %s\n'
1264 % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1265 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, iOp2X),));
1266 return;
1267
1268 def generateDivideErrorTests(self, oGen):
1269 """ Generate divide error tests (raises X86_XCPT_DE). """
1270 oGen.write('%ifdef VBINSTST_CAN_DO_TRAPS\n');
1271
1272 # We do one register variation here, assuming the standard test has got them covered.
1273 # Register tests
1274 if True:
1275 iOp2 = oGen.oTarget.randGRegNoSp();
1276 while iOp2 == X86_GREG_xAX or iOp2 == X86_GREG_xDX:
1277 iOp2 = oGen.oTarget.randGRegNoSp();
1278
1279 for cbEffOp in ( 8, 4, 2, 1 ):
1280 if cbEffOp > oGen.oTarget.getMaxOpBytes():
1281 continue;
1282 oGen.write('; cbEffOp=%u iOp2=%u\n' % (cbEffOp, iOp2,));
1283
1284 for iDividend, iDivisor in self.generateInputsXcpt(cbEffOp, fLong = not oGen.isTiny()):
1285 oGen.newSubTest();
1286 if cbEffOp > 1:
1287 self.generateOneDivideErrorTestGreg(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1288 else:
1289 self.generateOneDivideErrorTestGreg8Bit(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1290
1291 oGen.write('%endif ; VBINSTST_CAN_DO_TRAPS\n');
1292 return True;
1293
1294
1295 def generateTest(self, oGen, sTestFnName):
1296 oGen.write('VBINSTST_BEGINPROC %s\n' % (sTestFnName,));
1297 #oGen.write(' int3\n');
1298
1299 self.generateStandardTests(oGen);
1300 self.generateDivideErrorTests(oGen);
1301
1302 #oGen.write(' int3\n');
1303 oGen.write(' ret\n');
1304 oGen.write('VBINSTST_ENDPROC %s\n' % (sTestFnName,));
1305 return True;
1306
1307
1308
1309
1310##
1311# Instruction Tests.
1312#
1313g_aoInstructionTests = [
1314 InstrTest_Mov_Gv_Ev(),
1315 InstrTest_MovSxD_Gv_Ev(),
1316 InstrTest_DivIDiv(fIsIDiv = False),
1317 InstrTest_DivIDiv(fIsIDiv = True),
1318];
1319
1320
1321
1322
1323
1324class InstructionTestGen(object): # pylint: disable=R0902
1325 """
1326 Instruction Test Generator.
1327 """
1328
1329 ## @name Test size
1330 ## @{
1331 ksTestSize_Large = 'large';
1332 ksTestSize_Medium = 'medium';
1333 ksTestSize_Tiny = 'tiny';
1334 ## @}
1335 kasTestSizes = ( ksTestSize_Large, ksTestSize_Medium, ksTestSize_Tiny );
1336
1337
1338
1339 def __init__(self, oOptions):
1340 self.oOptions = oOptions;
1341 self.oTarget = g_dTargetEnvs[oOptions.sTargetEnv];
1342
1343 # Calculate the number of output files.
1344 self.cFiles = 1;
1345 if len(g_aoInstructionTests) > self.oOptions.cInstrPerFile:
1346 self.cFiles = len(g_aoInstructionTests) / self.oOptions.cInstrPerFile;
1347 if self.cFiles * self.oOptions.cInstrPerFile < len(g_aoInstructionTests):
1348 self.cFiles += 1;
1349
1350 # Fix the known register values.
1351 self.au64Regs = randUxxList(64, 16);
1352 self.au32Regs = [(self.au64Regs[i] & UINT32_MAX) for i in range(8)];
1353 self.au16Regs = [(self.au64Regs[i] & UINT16_MAX) for i in range(8)];
1354 self.auRegValues = self.au64Regs if self.oTarget.is64Bit() else self.au32Regs;
1355
1356 # Declare state variables used while generating.
1357 self.oFile = sys.stderr;
1358 self.iFile = -1;
1359 self.sFile = '';
1360 self._dCheckFns = dict();
1361 self._dMemSetupFns = dict();
1362 self._d64BitConsts = dict();
1363
1364 # State variables used while generating test convenientely placed here (lazy bird)...
1365 self.iModReg = 0;
1366 self.iModRm = 0;
1367 self.iSibBaseReg = 0;
1368 self.iSibIndexReg = 0;
1369 self.iSibScale = 1;
1370 if self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
1371 self._oModRegRange = range(2);
1372 self._oModRegRange8 = range(2);
1373 self.oModRmRange = range(2);
1374 self.cSibBasePerRun = 1;
1375 self._cSibIndexPerRun = 2;
1376 self.oSibScaleRange = range(1);
1377 elif self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
1378 self._oModRegRange = range( 5 if self.oTarget.is64Bit() else 4);
1379 self._oModRegRange8 = range( 6 if self.oTarget.is64Bit() else 4);
1380 self.oModRmRange = range(5);
1381 self.cSibBasePerRun = 5;
1382 self._cSibIndexPerRun = 4
1383 self.oSibScaleRange = range(2);
1384 else:
1385 self._oModRegRange = range(16 if self.oTarget.is64Bit() else 8);
1386 self._oModRegRange8 = range(20 if self.oTarget.is64Bit() else 8);
1387 self.oModRmRange = range(16 if self.oTarget.is64Bit() else 8);
1388 self.cSibBasePerRun = 8;
1389 self._cSibIndexPerRun = 9;
1390 self.oSibScaleRange = range(4);
1391 self.iSibIndexRange = 0;
1392
1393
1394 #
1395 # Methods used by instruction tests.
1396 #
1397
1398 def write(self, sText):
1399 """ Writes to the current output file. """
1400 return self.oFile.write(unicode(sText));
1401
1402 def writeln(self, sText):
1403 """ Writes a line to the current output file. """
1404 self.write(sText);
1405 return self.write('\n');
1406
1407 def writeInstrBytes(self, abInstr):
1408 """
1409 Emits an instruction given as a sequence of bytes values.
1410 """
1411 self.write(' db %#04x' % (abInstr[0],));
1412 for i in range(1, len(abInstr)):
1413 self.write(', %#04x' % (abInstr[i],));
1414 return self.write('\n');
1415
1416 def newSubTest(self):
1417 """
1418 Indicates that a new subtest has started.
1419 """
1420 self.write(' mov dword [VBINSTST_NAME(g_uVBInsTstSubTestIndicator) xWrtRIP], __LINE__\n');
1421 return True;
1422
1423 def needGRegChecker(self, iReg1, iReg2 = None, iReg3 = None):
1424 """
1425 Records the need for a given register checker function, returning its label.
1426 """
1427 if iReg2 is not None:
1428 if iReg3 is not None:
1429 sName = '%s_%s_%s' % (self.oTarget.asGRegs[iReg1], self.oTarget.asGRegs[iReg2], self.oTarget.asGRegs[iReg3],);
1430 else:
1431 sName = '%s_%s' % (self.oTarget.asGRegs[iReg1], self.oTarget.asGRegs[iReg2],);
1432 else:
1433 sName = '%s' % (self.oTarget.asGRegs[iReg1],);
1434 assert iReg3 is None;
1435
1436 if sName in self._dCheckFns:
1437 self._dCheckFns[sName] += 1;
1438 else:
1439 self._dCheckFns[sName] = 1;
1440
1441 return 'Common_Check_' + sName;
1442
1443 def needGRegMemSetup(self, cAddrBits, cbEffOp, iBaseReg = None, offDisp = None, iIndexReg = None, iScale = 1):
1444 """
1445 Records the need for a given register checker function, returning its label.
1446 """
1447 assert cAddrBits in [64, 32, 16];
1448 assert cbEffOp in [8, 4, 2, 1];
1449 assert iScale in [1, 2, 4, 8];
1450
1451 sName = '%ubit_U%u' % (cAddrBits, cbEffOp * 8,);
1452 if iBaseReg is not None:
1453 sName += '_%s' % (gregName(iBaseReg, cAddrBits),);
1454 sName += '_x%u' % (iScale,);
1455 if iIndexReg is not None:
1456 sName += '_%s' % (gregName(iIndexReg, cAddrBits),);
1457 if offDisp is not None:
1458 sName += '_%#010x' % (offDisp & UINT32_MAX, );
1459 if sName in self._dMemSetupFns:
1460 self._dMemSetupFns[sName] += 1;
1461 else:
1462 self._dMemSetupFns[sName] = 1;
1463 return 'Common_MemSetup_' + sName;
1464
1465 def need64BitConstant(self, uVal):
1466 """
1467 Records the need for a 64-bit constant, returning its label.
1468 These constants are pooled to attempt reduce the size of the whole thing.
1469 """
1470 assert uVal >= 0 and uVal <= UINT64_MAX;
1471 if uVal in self._d64BitConsts:
1472 self._d64BitConsts[uVal] += 1;
1473 else:
1474 self._d64BitConsts[uVal] = 1;
1475 return 'g_u64Const_0x%016x' % (uVal, );
1476
1477 def pushConst(self, uResult):
1478 """
1479 Emits a push constant value, taking care of high values on 64-bit hosts.
1480 """
1481 if self.oTarget.is64Bit() and uResult >= 0x80000000:
1482 self.write(' push qword [%s wrt rip]\n' % (self.need64BitConstant(uResult),));
1483 else:
1484 self.write(' push dword 0x%x\n' % (uResult,));
1485 return True;
1486
1487 def getDispForMod(self, iMod, cbAlignment = 1):
1488 """
1489 Get a set of address dispositions for a given addressing mode.
1490 The alignment restriction is for SIB scaling.
1491 """
1492 assert cbAlignment in [1, 2, 4, 8];
1493 if iMod == 0:
1494 aoffDisp = [ None, ];
1495 elif iMod == 1:
1496 aoffDisp = [ 127 & ~(cbAlignment - 1), -128 ];
1497 elif iMod == 2:
1498 aoffDisp = [ 2147483647 & ~(cbAlignment - 1), -2147483648 ];
1499 else: assert False;
1500 return aoffDisp;
1501
1502 def getModRegRange(self, cbEffOp):
1503 """
1504 The Mod R/M register range varies with the effective operand size, for
1505 8-bit registers we have 4 more.
1506 """
1507 if cbEffOp == 1:
1508 return self._oModRegRange8;
1509 return self._oModRegRange;
1510
1511 def getSibIndexPerRun(self):
1512 """
1513 We vary the SIB index test range a little to try cover more operand
1514 combinations and avoid repeating the same ones.
1515 """
1516 self.iSibIndexRange += 1;
1517 self.iSibIndexRange %= 3;
1518 if self.iSibIndexRange == 0:
1519 return self._cSibIndexPerRun - 1;
1520 return self._cSibIndexPerRun;
1521
1522 def isTiny(self):
1523 """ Checks if we're in tiny mode."""
1524 return self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny;
1525
1526
1527 #
1528 # Forwarding calls for oTarget to shorted typing and lessen the attacks
1529 # on the right margin.
1530 #
1531
1532 def gregNameBits(self, iReg, cBitsWide):
1533 """ Target: Get the name of a general register for the given size (in bits). """
1534 return self.oTarget.gregNameBits(iReg, cBitsWide);
1535
1536 def gregNameBytes(self, iReg, cbWide):
1537 """ Target: Get the name of a general register for the given size (in bytes). """
1538 return self.oTarget.gregNameBytes(iReg, cbWide);
1539
1540 def is64Bit(self):
1541 """ Target: Is the target 64-bit? """
1542 return self.oTarget.is64Bit();
1543
1544
1545 #
1546 # Internal machinery.
1547 #
1548
1549 def _randInitIndexes(self):
1550 """
1551 Initializes the Mod R/M and SIB state index with random numbers prior
1552 to generating a test.
1553
1554 Note! As with all other randomness and variations we do, we cannot
1555 test all combinations for each and every instruction so we try
1556 get coverage over time.
1557 """
1558 self.iModReg = randU8();
1559 self.iModRm = randU8();
1560 self.iSibBaseReg = randU8();
1561 self.iSibIndexReg = randU8();
1562 self.iSibScale = 1 << (randU8() & 3);
1563 self.iSibIndexRange = randU8();
1564 return True;
1565
1566 def _calcTestFunctionName(self, oInstrTest, iInstrTest):
1567 """
1568 Calc a test function name for the given instruction test.
1569 """
1570 sName = 'TestInstr%03u_%s' % (iInstrTest, oInstrTest.sName);
1571 return sName.replace(',', '_').replace(' ', '_').replace('%', '_');
1572
1573 def _generateFileHeader(self, ):
1574 """
1575 Writes the file header.
1576 Raises exception on trouble.
1577 """
1578 self.write('; $Id: InstructionTestGen.py 48346 2013-09-06 09:50:19Z vboxsync $\n'
1579 ';; @file %s\n'
1580 '; Autogenerate by %s %s. DO NOT EDIT\n'
1581 ';\n'
1582 '\n'
1583 ';\n'
1584 '; Headers\n'
1585 ';\n'
1586 '%%include "env-%s.mac"\n'
1587 % ( os.path.basename(self.sFile),
1588 os.path.basename(__file__), __version__[11:-1],
1589 self.oTarget.sName,
1590 ) );
1591 # Target environment specific init stuff.
1592
1593 #
1594 # Global variables.
1595 #
1596 self.write('\n\n'
1597 ';\n'
1598 '; Globals\n'
1599 ';\n');
1600 self.write('VBINSTST_BEGINDATA\n'
1601 'VBINSTST_GLOBALNAME_EX g_pvLow16Mem4K, data hidden\n'
1602 ' dq 0\n'
1603 'VBINSTST_GLOBALNAME_EX g_pvLow32Mem4K, data hidden\n'
1604 ' dq 0\n'
1605 'VBINSTST_GLOBALNAME_EX g_pvMem4K, data hidden\n'
1606 ' dq 0\n'
1607 'VBINSTST_GLOBALNAME_EX g_uVBInsTstSubTestIndicator, data hidden\n'
1608 ' dd 0\n'
1609 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
1610 'VBINSTST_TRAP_RECS_BEGIN\n'
1611 '%endif\n'
1612 'VBINSTST_BEGINCODE\n'
1613 );
1614 self.write('%ifdef RT_ARCH_AMD64\n');
1615 for i in range(len(g_asGRegs64)):
1616 self.write('g_u64KnownValue_%s: dq 0x%x\n' % (g_asGRegs64[i], self.au64Regs[i]));
1617 self.write('%endif\n\n')
1618
1619 #
1620 # Common functions.
1621 #
1622
1623 # Loading common values.
1624 self.write('\n\n'
1625 'VBINSTST_BEGINPROC Common_LoadKnownValues\n'
1626 '%ifdef RT_ARCH_AMD64\n');
1627 for i in range(len(g_asGRegs64NoSp)):
1628 if g_asGRegs64NoSp[i]:
1629 self.write(' mov %s, 0x%x\n' % (g_asGRegs64NoSp[i], self.au64Regs[i],));
1630 self.write('%else\n');
1631 for i in range(8):
1632 if g_asGRegs32NoSp[i]:
1633 self.write(' mov %s, 0x%x\n' % (g_asGRegs32NoSp[i], self.au32Regs[i],));
1634 self.write('%endif\n'
1635 ' ret\n'
1636 'VBINSTST_ENDPROC Common_LoadKnownValues\n'
1637 '\n');
1638
1639 self.write('VBINSTST_BEGINPROC Common_CheckKnownValues\n'
1640 '%ifdef RT_ARCH_AMD64\n');
1641 for i in range(len(g_asGRegs64NoSp)):
1642 if g_asGRegs64NoSp[i]:
1643 self.write(' cmp %s, [g_u64KnownValue_%s wrt rip]\n'
1644 ' je .ok_%u\n'
1645 ' push %u ; register number\n'
1646 ' push %s ; actual\n'
1647 ' push qword [g_u64KnownValue_%s wrt rip] ; expected\n'
1648 ' call VBINSTST_NAME(Common_BadValue)\n'
1649 '.ok_%u:\n'
1650 % ( g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i, i, g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i,));
1651 self.write('%else\n');
1652 for i in range(8):
1653 if g_asGRegs32NoSp[i]:
1654 self.write(' cmp %s, 0x%x\n'
1655 ' je .ok_%u\n'
1656 ' push %u ; register number\n'
1657 ' push %s ; actual\n'
1658 ' push dword 0x%x ; expected\n'
1659 ' call VBINSTST_NAME(Common_BadValue)\n'
1660 '.ok_%u:\n'
1661 % ( g_asGRegs32NoSp[i], self.au32Regs[i], i, i, g_asGRegs32NoSp[i], self.au32Regs[i], i,));
1662 self.write('%endif\n'
1663 ' ret\n'
1664 'VBINSTST_ENDPROC Common_CheckKnownValues\n'
1665 '\n');
1666
1667 return True;
1668
1669 def _generateMemSetupFunctions(self): # pylint: disable=R0915
1670 """
1671 Generates the memory setup functions.
1672 """
1673 cDefAddrBits = self.oTarget.getDefAddrBits();
1674 for sName in self._dMemSetupFns:
1675 # Unpack it.
1676 asParams = sName.split('_');
1677 cAddrBits = int(asParams[0][:-3]); assert asParams[0][-3:] == 'bit';
1678 cEffOpBits = int(asParams[1][1:]); assert asParams[1][0] == 'U';
1679 if cAddrBits == 64: asAddrGRegs = g_asGRegs64;
1680 elif cAddrBits == 32: asAddrGRegs = g_asGRegs32;
1681 else: asAddrGRegs = g_asGRegs16;
1682
1683 i = 2;
1684 iBaseReg = None;
1685 sBaseReg = None;
1686 if i < len(asParams) and asParams[i] in asAddrGRegs:
1687 sBaseReg = asParams[i];
1688 iBaseReg = asAddrGRegs.index(sBaseReg);
1689 i += 1
1690
1691 assert i < len(asParams); assert asParams[i][0] == 'x';
1692 iScale = iScale = int(asParams[i][1:]); assert iScale in [1, 2, 4, 8], '%u %s' % (iScale, sName);
1693 i += 1;
1694
1695 sIndexReg = None;
1696 iIndexReg = None;
1697 if i < len(asParams) and asParams[i] in asAddrGRegs:
1698 sIndexReg = asParams[i];
1699 iIndexReg = asAddrGRegs.index(sIndexReg);
1700 i += 1;
1701
1702 u32Disp = None;
1703 if i < len(asParams) and len(asParams[i]) == 10:
1704 u32Disp = long(asParams[i], 16);
1705 i += 1;
1706
1707 assert i == len(asParams), 'i=%d len=%d len[i]=%d (%s)' % (i, len(asParams), len(asParams[i]), asParams[i],);
1708 assert iScale == 1 or iIndexReg is not None;
1709
1710 # Find a temporary register.
1711 iTmpReg1 = X86_GREG_xCX;
1712 while iTmpReg1 in [iBaseReg, iIndexReg]:
1713 iTmpReg1 += 1;
1714
1715 # Prologue.
1716 self.write('\n\n'
1717 '; cAddrBits=%s cEffOpBits=%s iBaseReg=%s u32Disp=%s iIndexReg=%s iScale=%s\n'
1718 'VBINSTST_BEGINPROC Common_MemSetup_%s\n'
1719 ' MY_PUSH_FLAGS\n'
1720 ' push %s\n'
1721 % ( cAddrBits, cEffOpBits, iBaseReg, u32Disp, iIndexReg, iScale,
1722 sName, self.oTarget.asGRegs[iTmpReg1], ));
1723
1724 # Figure out what to use.
1725 if cEffOpBits == 64:
1726 sTmpReg1 = g_asGRegs64[iTmpReg1];
1727 sDataVar = 'VBINSTST_NAME(g_u64Data)';
1728 elif cEffOpBits == 32:
1729 sTmpReg1 = g_asGRegs32[iTmpReg1];
1730 sDataVar = 'VBINSTST_NAME(g_u32Data)';
1731 elif cEffOpBits == 16:
1732 sTmpReg1 = g_asGRegs16[iTmpReg1];
1733 sDataVar = 'VBINSTST_NAME(g_u16Data)';
1734 else:
1735 assert cEffOpBits == 8; assert iTmpReg1 < 4;
1736 sTmpReg1 = g_asGRegs8Rex[iTmpReg1];
1737 sDataVar = 'VBINSTST_NAME(g_u8Data)';
1738
1739 # Special case: reg + reg * [2,4,8]
1740 if iBaseReg == iIndexReg and iBaseReg is not None and iScale != 1:
1741 iTmpReg2 = X86_GREG_xBP;
1742 while iTmpReg2 in [iBaseReg, iIndexReg, iTmpReg1]:
1743 iTmpReg2 += 1;
1744 sTmpReg2 = self.gregNameBits(iTmpReg2, cAddrBits);
1745 self.write(' push sAX\n'
1746 ' push %s\n'
1747 ' push sDX\n'
1748 % (self.oTarget.asGRegs[iTmpReg2],));
1749 if cAddrBits == 16:
1750 self.write(' mov %s, [VBINSTST_NAME(g_pvLow16Mem4K) xWrtRIP]\n' % (sTmpReg2,));
1751 else:
1752 self.write(' mov %s, [VBINSTST_NAME(g_pvLow32Mem4K) xWrtRIP]\n' % (sTmpReg2,));
1753 self.write(' add %s, 0x200\n' % (sTmpReg2,));
1754 self.write(' mov %s, %s\n' % (self.gregNameBits(X86_GREG_xAX, cAddrBits), sTmpReg2,));
1755 if u32Disp is not None:
1756 self.write(' sub %s, %d\n'
1757 % ( self.gregNameBits(X86_GREG_xAX, cAddrBits), convU32ToSigned(u32Disp), ));
1758 self.write(' xor edx, edx\n'
1759 '%if xCB == 2\n'
1760 ' push 0\n'
1761 '%endif\n');
1762 self.write(' push %u\n' % (iScale + 1,));
1763 self.write(' div %s [xSP]\n' % ('qword' if cAddrBits == 64 else 'dword',));
1764 self.write(' sub %s, %s\n' % (sTmpReg2, self.gregNameBits(X86_GREG_xDX, cAddrBits),));
1765 self.write(' pop sDX\n'
1766 ' pop sDX\n'); # sTmpReg2 is eff address; sAX is sIndexReg value.
1767 # Note! sTmpReg1 can be xDX and that's no problem now.
1768 self.write(' mov %s, [xSP + sCB*3 + MY_PUSH_FLAGS_SIZE + xCB]\n' % (sTmpReg1,));
1769 self.write(' mov [%s], %s\n' % (sTmpReg2, sTmpReg1,)); # Value in place.
1770 self.write(' pop %s\n' % (self.oTarget.asGRegs[iTmpReg2],));
1771 if iBaseReg == X86_GREG_xAX:
1772 self.write(' pop %s\n' % (self.oTarget.asGRegs[iTmpReg1],));
1773 else:
1774 self.write(' mov %s, %s\n' % (sBaseReg, self.gregNameBits(X86_GREG_xAX, cAddrBits),));
1775 self.write(' pop sAX\n');
1776
1777 else:
1778 # Load the value and mem address, storing the value there.
1779 # Note! ASSUMES that the scale and disposition works fine together.
1780 sAddrReg = sBaseReg if sBaseReg is not None else sIndexReg;
1781 self.write(' mov %s, [xSP + sCB + MY_PUSH_FLAGS_SIZE + xCB]\n' % (sTmpReg1,));
1782 if cAddrBits >= cDefAddrBits:
1783 self.write(' mov [%s xWrtRIP], %s\n' % (sDataVar, sTmpReg1,));
1784 self.write(' lea %s, [%s xWrtRIP]\n' % (sAddrReg, sDataVar,));
1785 else:
1786 if cAddrBits == 16:
1787 self.write(' mov %s, [VBINSTST_NAME(g_pvLow16Mem4K) xWrtRIP]\n' % (sAddrReg,));
1788 else:
1789 self.write(' mov %s, [VBINSTST_NAME(g_pvLow32Mem4K) xWrtRIP]\n' % (sAddrReg,));
1790 self.write(' add %s, %s\n' % (sAddrReg, (randU16() << cEffOpBits) & 0xfff, ));
1791 self.write(' mov [%s], %s\n' % (sAddrReg, sTmpReg1, ));
1792
1793 # Adjust for disposition and scaling.
1794 if u32Disp is not None:
1795 self.write(' sub %s, %d\n' % ( sAddrReg, convU32ToSigned(u32Disp), ));
1796 if iIndexReg is not None:
1797 if iBaseReg == iIndexReg:
1798 assert iScale == 1;
1799 assert u32Disp is None or (u32Disp & 1) == 0;
1800 self.write(' shr %s, 1\n' % (sIndexReg,));
1801 elif sBaseReg is not None:
1802 uIdxRegVal = randUxx(cAddrBits);
1803 if cAddrBits == 64:
1804 self.write(' mov %s, %u\n'
1805 ' sub %s, %s\n'
1806 ' mov %s, %u\n'
1807 % ( sIndexReg, (uIdxRegVal * iScale) & UINT64_MAX,
1808 sBaseReg, sIndexReg,
1809 sIndexReg, uIdxRegVal, ));
1810 else:
1811 assert cAddrBits == 32;
1812 self.write(' mov %s, %u\n'
1813 ' sub %s, %#06x\n'
1814 % ( sIndexReg, uIdxRegVal, sBaseReg, (uIdxRegVal * iScale) & UINT32_MAX, ));
1815 elif iScale == 2:
1816 assert u32Disp is None or (u32Disp & 1) == 0;
1817 self.write(' shr %s, 1\n' % (sIndexReg,));
1818 elif iScale == 4:
1819 assert u32Disp is None or (u32Disp & 3) == 0;
1820 self.write(' shr %s, 2\n' % (sIndexReg,));
1821 elif iScale == 8:
1822 assert u32Disp is None or (u32Disp & 7) == 0;
1823 self.write(' shr %s, 3\n' % (sIndexReg,));
1824 else:
1825 assert iScale == 1;
1826
1827 # Set upper bits that's supposed to be unused.
1828 if cDefAddrBits > cAddrBits or cAddrBits == 16:
1829 if cDefAddrBits == 64:
1830 assert cAddrBits == 32;
1831 if iBaseReg is not None:
1832 self.write(' mov %s, %#018x\n'
1833 ' or %s, %s\n'
1834 % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
1835 g_asGRegs64[iBaseReg], g_asGRegs64[iTmpReg1],));
1836 if iIndexReg is not None and iIndexReg != iBaseReg:
1837 self.write(' mov %s, %#018x\n'
1838 ' or %s, %s\n'
1839 % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
1840 g_asGRegs64[iIndexReg], g_asGRegs64[iTmpReg1],));
1841 else:
1842 assert cDefAddrBits == 32; assert cAddrBits == 16; assert iIndexReg is None;
1843 if iBaseReg is not None:
1844 self.write(' or %s, %#010x\n'
1845 % ( g_asGRegs32[iBaseReg], randU32() & 0xffff0000, ));
1846
1847 # Epilogue.
1848 self.write(' pop %s\n'
1849 ' MY_POP_FLAGS\n'
1850 ' ret sCB\n'
1851 'VBINSTST_ENDPROC Common_MemSetup_%s\n'
1852 % ( self.oTarget.asGRegs[iTmpReg1], sName,));
1853
1854
1855 def _generateFileFooter(self):
1856 """
1857 Generates file footer.
1858 """
1859
1860 # Terminate the trap records.
1861 self.write('\n\n'
1862 ';\n'
1863 '; Terminate the trap records\n'
1864 ';\n'
1865 'VBINSTST_BEGINDATA\n'
1866 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
1867 'VBINSTST_TRAP_RECS_END\n'
1868 '%endif\n'
1869 'VBINSTST_BEGINCODE\n');
1870
1871 # Register checking functions.
1872 for sName in self._dCheckFns:
1873 asRegs = sName.split('_');
1874 sPushSize = 'dword';
1875
1876 # Prologue
1877 self.write('\n\n'
1878 '; Checks 1 or more register values, expected values pushed on the stack.\n'
1879 '; To save space, the callee cleans up the stack.'
1880 '; Ref count: %u\n'
1881 'VBINSTST_BEGINPROC Common_Check_%s\n'
1882 ' MY_PUSH_FLAGS\n'
1883 % ( self._dCheckFns[sName], sName, ) );
1884
1885 # Register checks.
1886 for i in range(len(asRegs)):
1887 sReg = asRegs[i];
1888 iReg = self.oTarget.asGRegs.index(sReg);
1889 if i == asRegs.index(sReg): # Only check once, i.e. input = output reg.
1890 self.write(' cmp %s, [xSP + MY_PUSH_FLAGS_SIZE + xCB + sCB * %u]\n'
1891 ' je .equal%u\n'
1892 ' push %s %u ; register number\n'
1893 ' push %s ; actual\n'
1894 ' mov %s, [xSP + sCB*2 + MY_PUSH_FLAGS_SIZE + xCB + sCB * %u]\n'
1895 ' push %s ; expected\n'
1896 ' call VBINSTST_NAME(Common_BadValue)\n'
1897 '.equal%u:\n'
1898 % ( sReg, i, i, sPushSize, iReg, sReg, sReg, i, sReg, i, ) );
1899
1900
1901 # Restore known register values and check the other registers.
1902 for sReg in asRegs:
1903 if self.oTarget.is64Bit():
1904 self.write(' mov %s, [g_u64KnownValue_%s wrt rip]\n' % (sReg, sReg,));
1905 else:
1906 iReg = self.oTarget.asGRegs.index(sReg)
1907 self.write(' mov %s, 0x%x\n' % (sReg, self.au32Regs[iReg],));
1908 self.write(' MY_POP_FLAGS\n'
1909 ' call VBINSTST_NAME(Common_CheckKnownValues)\n'
1910 ' ret sCB*%u\n'
1911 'VBINSTST_ENDPROC Common_Check_%s\n'
1912 % (len(asRegs), sName,));
1913
1914 # memory setup functions
1915 self._generateMemSetupFunctions();
1916
1917 # 64-bit constants.
1918 if len(self._d64BitConsts) > 0:
1919 self.write('\n\n'
1920 ';\n'
1921 '; 64-bit constants\n'
1922 ';\n');
1923 for uVal in self._d64BitConsts:
1924 self.write('g_u64Const_0x%016x: dq 0x%016x ; Ref count: %d\n' % (uVal, uVal, self._d64BitConsts[uVal], ) );
1925
1926 return True;
1927
1928 def _generateTests(self):
1929 """
1930 Generate the test cases.
1931 """
1932 for self.iFile in range(self.cFiles):
1933 if self.cFiles == 1:
1934 self.sFile = '%s.asm' % (self.oOptions.sOutputBase,)
1935 else:
1936 self.sFile = '%s-%u.asm' % (self.oOptions.sOutputBase, self.iFile)
1937 self.oFile = sys.stdout;
1938 if self.oOptions.sOutputBase != '-':
1939 self.oFile = io.open(self.sFile, 'w', buffering = 65536, encoding = 'utf-8');
1940
1941 self._generateFileHeader();
1942
1943 # Calc the range.
1944 iInstrTestStart = self.iFile * self.oOptions.cInstrPerFile;
1945 iInstrTestEnd = iInstrTestStart + self.oOptions.cInstrPerFile;
1946 if iInstrTestEnd > len(g_aoInstructionTests):
1947 iInstrTestEnd = len(g_aoInstructionTests);
1948
1949 # Generate the instruction tests.
1950 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1951 oInstrTest = g_aoInstructionTests[iInstrTest];
1952 self.write('\n'
1953 '\n'
1954 ';\n'
1955 '; %s\n'
1956 ';\n'
1957 % (oInstrTest.sName,));
1958 self._randInitIndexes();
1959 oInstrTest.generateTest(self, self._calcTestFunctionName(oInstrTest, iInstrTest));
1960
1961 # Generate the main function.
1962 self.write('\n\n'
1963 'VBINSTST_BEGINPROC TestInstrMain\n'
1964 ' MY_PUSH_ALL\n'
1965 ' sub xSP, 40h\n'
1966 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
1967 ' VBINSTST_TRAP_RECS_INSTALL\n'
1968 '%endif\n'
1969 '\n');
1970
1971 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1972 oInstrTest = g_aoInstructionTests[iInstrTest];
1973 if oInstrTest.isApplicable(self):
1974 self.write('%%ifdef ASM_CALL64_GCC\n'
1975 ' lea rdi, [.szInstr%03u wrt rip]\n'
1976 '%%elifdef ASM_CALL64_MSC\n'
1977 ' lea rcx, [.szInstr%03u wrt rip]\n'
1978 '%%else\n'
1979 ' mov xAX, .szInstr%03u\n'
1980 ' mov [xSP], xAX\n'
1981 '%%endif\n'
1982 ' VBINSTST_CALL_FN_SUB_TEST\n'
1983 ' call VBINSTST_NAME(%s)\n'
1984 % ( iInstrTest, iInstrTest, iInstrTest, self._calcTestFunctionName(oInstrTest, iInstrTest)));
1985
1986 self.write('\n'
1987 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
1988 ' VBINSTST_TRAP_RECS_UNINSTALL\n'
1989 '%endif\n'
1990 ' add xSP, 40h\n'
1991 ' MY_POP_ALL\n'
1992 ' ret\n\n');
1993 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1994 self.write('.szInstr%03u: db \'%s\', 0\n' % (iInstrTest, g_aoInstructionTests[iInstrTest].sName,));
1995 self.write('VBINSTST_ENDPROC TestInstrMain\n\n');
1996
1997 self._generateFileFooter();
1998 if self.oOptions.sOutputBase != '-':
1999 self.oFile.close();
2000 self.oFile = None;
2001 self.sFile = '';
2002
2003 return RTEXITCODE_SUCCESS;
2004
2005 def _runMakefileMode(self):
2006 """
2007 Generate a list of output files on standard output.
2008 """
2009 if self.cFiles == 1:
2010 print('%s.asm' % (self.oOptions.sOutputBase,));
2011 else:
2012 print(' '.join('%s-%s.asm' % (self.oOptions.sOutputBase, i) for i in range(self.cFiles)));
2013 return RTEXITCODE_SUCCESS;
2014
2015 def run(self):
2016 """
2017 Generates the tests or whatever is required.
2018 """
2019 if self.oOptions.fMakefileMode:
2020 return self._runMakefileMode();
2021 sys.stderr.write('InstructionTestGen.py: Seed = %s\n' % (g_iMyRandSeed,));
2022 return self._generateTests();
2023
2024 @staticmethod
2025 def main():
2026 """
2027 Main function a la C/C++. Returns exit code.
2028 """
2029
2030 #
2031 # Parse the command line.
2032 #
2033 oParser = OptionParser(version = __version__[11:-1].strip());
2034 oParser.add_option('--makefile-mode', dest = 'fMakefileMode', action = 'store_true', default = False,
2035 help = 'Special mode for use to output a list of output files for the benefit of '
2036 'the make program (kmk).');
2037 oParser.add_option('--split', dest = 'cInstrPerFile', metavar = '<instr-per-file>', type = 'int', default = 9999999,
2038 help = 'Number of instruction to test per output file.');
2039 oParser.add_option('--output-base', dest = 'sOutputBase', metavar = '<file>', default = None,
2040 help = 'The output file base name, no suffix please. Required.');
2041 oParser.add_option('--target', dest = 'sTargetEnv', metavar = '<target>',
2042 default = 'iprt-r3-32',
2043 choices = g_dTargetEnvs.keys(),
2044 help = 'The target environment. Choices: %s'
2045 % (', '.join(sorted(g_dTargetEnvs.keys())),));
2046 oParser.add_option('--test-size', dest = 'sTestSize', default = InstructionTestGen.ksTestSize_Medium,
2047 choices = InstructionTestGen.kasTestSizes,
2048 help = 'Selects the test size.');
2049
2050 (oOptions, asArgs) = oParser.parse_args();
2051 if len(asArgs) > 0:
2052 oParser.print_help();
2053 return RTEXITCODE_SYNTAX
2054 if oOptions.sOutputBase is None:
2055 print('syntax error: Missing required option --output-base.', file = sys.stderr);
2056 return RTEXITCODE_SYNTAX
2057
2058 #
2059 # Instantiate the program class and run it.
2060 #
2061 oProgram = InstructionTestGen(oOptions);
2062 return oProgram.run();
2063
2064
2065if __name__ == '__main__':
2066 sys.exit(InstructionTestGen.main());
2067
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