VirtualBox

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

Last change on this file since 47389 was 47287, checked in by vboxsync, 12 years ago

Back to the MOVXSD instruction.

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