VirtualBox

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

最後變更 在這個檔案從47139是 47139,由 vboxsync 提交於 11 年 前

iem: Fixed negation of number in two registers.

  • 屬性 svn:eol-style 設為 LF
  • 屬性 svn:executable 設為 *
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 86.9 KB
 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: InstructionTestGen.py 47139 2013-07-14 19:54:23Z 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: 47139 $";
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
491 ## @name Test Instruction Writers
492 ## @{
493
494 def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
495 """ Writes the instruction with two general registers as operands. """
496 fRexByteRegs = oGen.oTarget.is64Bit();
497 oGen.write(' %s %s, %s\n'
498 % (self.sInstr, gregName(iOp1, cbEffOp * 8, fRexByteRegs), gregName(iOp2, cbEffOp * 8, fRexByteRegs),));
499 return True;
500
501 def writeInstrGregPureRM(self, cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen):
502 """ Writes the instruction with two general registers as operands. """
503 oGen.write(' ');
504 if iOp2 == 13 and iMod == 0 and cAddrBits == 64:
505 oGen.write('altrexb '); # Alternative encoding for rip relative addressing.
506 if cbEffOp == 8:
507 oGen.write('%s %s, [' % (self.sInstr, g_asGRegs64[iOp1],));
508 elif cbEffOp == 4:
509 oGen.write('%s %s, [' % (self.sInstr, g_asGRegs32[iOp1],));
510 elif cbEffOp == 2:
511 oGen.write('%s %s, [' % (self.sInstr, g_asGRegs16[iOp1],));
512 elif cbEffOp == 1:
513 oGen.write('%s %s, [' % (self.sInstr, g_asGRegs8Rex[iOp1],));
514 else:
515 assert False;
516
517 if (iOp2 == 5 or iOp2 == 13) and iMod == 0:
518 oGen.write('VBINSTST_NAME(g_u%sData)' % (cbEffOp * 8,))
519 if oGen.oTarget.is64Bit():
520 oGen.write(' wrt rip');
521 else:
522 if iMod == 1:
523 oGen.write('byte %d + ' % (offDisp,));
524 elif iMod == 2:
525 oGen.write('dword %d + ' % (offDisp,));
526 else:
527 assert iMod == 0;
528
529 if cAddrBits == 64:
530 oGen.write(g_asGRegs64[iOp2]);
531 elif cAddrBits == 32:
532 oGen.write(g_asGRegs32[iOp2]);
533 elif cAddrBits == 16:
534 assert False; ## @todo implement 16-bit addressing.
535 else:
536 assert False, str(cAddrBits);
537
538 oGen.write(']\n');
539 return True;
540
541 def writeInstrGregSibLabel(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
542 """ Writes the instruction taking a register and a label (base only w/o reg), SIB form. """
543 assert offDisp is None; assert iBaseReg in [5, 13]; assert iIndexReg == 4; assert cAddrBits != 16;
544 if cAddrBits == 64:
545 # Note! Cannot test this in 64-bit mode in any sensible way because the disp is 32-bit
546 # and we cannot (yet) make assumtions about where we're loaded.
547 ## @todo Enable testing this in environments where we can make assumptions (boot sector).
548 oGen.write(' %s %s, [VBINSTST_NAME(g_u%sData) xWrtRIP]\n'
549 % ( self.sInstr, gregName(iOp1, cbEffOp * 8), cbEffOp * 8,));
550 else:
551 oGen.write(' altsibx%u %s %s, [VBINSTST_NAME(g_u%sData) xWrtRIP]\n'
552 % ( iScale, self.sInstr, gregName(iOp1, cbEffOp * 8), cbEffOp * 8,));
553 return True;
554
555 def writeInstrGregSibScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
556 """ Writes the instruction taking a register and disp+scaled register (no base reg), SIB form. """
557 assert iBaseReg in [5, 13]; assert iIndexReg != 4; assert cAddrBits != 16;
558 # Note! Using altsibxN to force scaled encoding. This is only really a
559 # necessity for iScale=1, but doesn't hurt for the rest.
560 oGen.write(' altsibx%u %s %s, [%s * %#x'
561 % (iScale, self.sInstr, gregName(iOp1, cbEffOp * 8), gregName(iIndexReg, cAddrBits), iScale,));
562 if offDisp is not None:
563 oGen.write(' + %#x' % (offDisp,));
564 oGen.write(']\n');
565 _ = iBaseReg;
566 return True;
567
568 def writeInstrGregSibBase(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
569 """ Writes the instruction taking a register and base only (with reg), SIB form. """
570 oGen.write(' altsibx%u %s %s, [%s'
571 % (iScale, self.sInstr, gregName(iOp1, cbEffOp * 8), gregName(iBaseReg, cAddrBits),));
572 if offDisp is not None:
573 oGen.write(' + %#x' % (offDisp,));
574 oGen.write(']\n');
575 _ = iIndexReg;
576 return True;
577
578 def writeInstrGregSibBaseAndScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
579 """ Writes tinstruction taking a register and full featured SIB form address. """
580 # Note! From the looks of things, yasm will encode the following instructions the same way:
581 # mov eax, [rsi*1 + rbx]
582 # mov eax, [rbx + rsi*1]
583 # So, when there are two registers involved, the '*1' selects
584 # which is index and which is base.
585 oGen.write(' %s %s, [%s + %s * %u'
586 % ( self.sInstr, gregName(iOp1, cbEffOp * 8),
587 gregName(iBaseReg, cAddrBits), gregName(iIndexReg, cAddrBits), iScale,));
588 if offDisp is not None:
589 oGen.write(' + %#x' % (offDisp,));
590 oGen.write(']\n');
591 return True;
592
593 ## @}
594
595
596 ## @name Memory setups
597 ## @{
598 def generateMemSetupReadByLabel(self, oGen, cbEffOp, uInput):
599 """ Sets up memory for a memory read. """
600 oGen.pushConst(uInput);
601 oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
602 return True;
603
604 def generateMemSetupReadByReg(self, oGen, cAddrBits, cbEffOp, iReg1, 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, iBaseReg = iReg1, offDisp = offDisp),));
609 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iReg1],));
610 return True;
611
612 def generateMemSetupReadByScaledReg(self, oGen, cAddrBits, cbEffOp, iIndexReg, iScale, uInput, offDisp = None):
613 """ Sets up memory for a memory read indirectly addressed thru one register and optional displacement. """
614 oGen.pushConst(uInput);
615 oGen.write(' call VBINSTST_NAME(%s)\n'
616 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, offDisp = offDisp, iIndexReg = iIndexReg, iScale = iScale),));
617 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iIndexReg],));
618 return True;
619
620 def generateMemSetupReadByBaseAndScaledReg(self, oGen, cAddrBits, cbEffOp, iBaseReg, iIndexReg, iScale, uInput, offDisp):
621 """ Sets up memory for a memory read indirectly addressed thru two registers with optional displacement. """
622 oGen.pushConst(uInput);
623 oGen.write(' call VBINSTST_NAME(%s)\n'
624 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iBaseReg = iBaseReg, offDisp = offDisp,
625 iIndexReg = iIndexReg, iScale = iScale),));
626 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iIndexReg],));
627 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iBaseReg],));
628 return True;
629
630 def generateMemSetupPureRM(self, oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp = None):
631 """ Sets up memory for a pure R/M addressed read, iOp2 being the R/M value. """
632 oGen.pushConst(uInput);
633 assert offDisp is None or iMod != 0;
634 if (iOp2 != 5 and iOp2 != 13) or iMod != 0:
635 oGen.write(' call VBINSTST_NAME(%s)\n'
636 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iOp2, offDisp),));
637 else:
638 oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
639 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
640 return True;
641
642 ## @}
643
644 def generateOneStdTestGregGreg(self, oGen, cbEffOp, cbMaxOp, iOp1, iOp1X, iOp2, iOp2X, uInput, uResult):
645 """ Generate one standard instr greg,greg test. """
646 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
647 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uInput,));
648 if iOp1X != iOp2X:
649 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
650 self.writeInstrGregGreg(cbEffOp, iOp1, iOp2, oGen);
651 oGen.pushConst(uResult);
652 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1X, iOp2X if iOp1X != iOp2X else None),));
653 _ = cbMaxOp;
654 return True;
655
656 def generateOneStdTestGregGreg8BitHighPain(self, oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput):
657 """ High 8-bit registers are a real pain! """
658 assert oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) or oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2);
659 # Figure out the register indexes of the max op sized regs involved.
660 iOp1X = iOp1 & 3;
661 iOp2X = iOp2 & 3;
662 oGen.write(' ; iOp1=%u iOp1X=%u iOp2=%u iOp2X=%u\n' % (iOp1, iOp1X, iOp2, iOp2X,));
663
664 # Calculate unshifted result.
665 if iOp1X != iOp2X:
666 uCur = oGen.auRegValues[iOp1X];
667 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1):
668 uCur = rotateRightUxx(cbMaxOp * 8, uCur, 8);
669 else:
670 uCur = uInput;
671 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) != oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
672 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1):
673 uCur = rotateRightUxx(cbMaxOp * 8, uCur, 8);
674 else:
675 uCur = rotateLeftUxx(cbMaxOp * 8, uCur, 8);
676 uResult = self.fnCalcResult(cbEffOp, uInput, uCur, oGen);
677
678
679 # Rotate the input and/or result to match their max-op-sized registers.
680 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
681 uInput = rotateLeftUxx(cbMaxOp * 8, uInput, 8);
682 if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1):
683 uResult = rotateLeftUxx(cbMaxOp * 8, uResult, 8);
684
685 # Hand it over to an overridable worker method.
686 return self.generateOneStdTestGregGreg(oGen, cbEffOp, cbMaxOp, iOp1, iOp1X, iOp2, iOp2X, uInput, uResult);
687
688
689 def generateOneStdTestGregMemNoSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iOp2, uInput, uResult):
690 """ Generate mode 0, 1 and 2 test for the R/M=iOp2. """
691 if cAddrBits == 16:
692 _ = cbMaxOp;
693 else:
694 iMod = 0; # No disp, except for i=5.
695 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
696 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput);
697 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, None, oGen);
698 oGen.pushConst(uResult);
699 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
700
701 if iOp2 != 5 and iOp2 != 13:
702 iMod = 1;
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 iMod = 2;
711 for offDisp in oGen.getDispForMod(iMod):
712 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
713 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp);
714 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen);
715 oGen.pushConst(uResult);
716 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
717
718 return True;
719
720 def generateOneStdTestGregMemSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod, # pylint: disable=R0913
721 iBaseReg, iIndexReg, iScale, uInput, uResult):
722 """ Generate one SIB variations. """
723 for offDisp in oGen.getDispForMod(iMod, cbEffOp):
724 if ((iBaseReg == 5 or iBaseReg == 13) and iMod == 0):
725 if iIndexReg == 4:
726 if cAddrBits == 64:
727 continue; # skipping.
728 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
729 self.generateMemSetupReadByLabel(oGen, cbEffOp, uInput);
730 self.writeInstrGregSibLabel(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
731 sChecker = oGen.needGRegChecker(iOp1);
732 else:
733 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
734 self.generateMemSetupReadByScaledReg(oGen, cAddrBits, cbEffOp, iIndexReg, iScale, uInput, offDisp);
735 self.writeInstrGregSibScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
736 sChecker = oGen.needGRegChecker(iOp1, iIndexReg);
737 else:
738 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
739 if iIndexReg == 4:
740 self.generateMemSetupReadByReg(oGen, cAddrBits, cbEffOp, iBaseReg, uInput, offDisp);
741 self.writeInstrGregSibBase(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
742 sChecker = oGen.needGRegChecker(iOp1, iBaseReg);
743 else:
744 if iIndexReg == iBaseReg and iScale == 1 and offDisp is not None and (offDisp & 1):
745 if offDisp < 0: offDisp += 1;
746 else: offDisp -= 1;
747 self.generateMemSetupReadByBaseAndScaledReg(oGen, cAddrBits, cbEffOp, iBaseReg,
748 iIndexReg, iScale, uInput, offDisp);
749 self.writeInstrGregSibBaseAndScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
750 sChecker = oGen.needGRegChecker(iOp1, iBaseReg, iIndexReg);
751 oGen.pushConst(uResult);
752 oGen.write(' call VBINSTST_NAME(%s)\n' % (sChecker,));
753 _ = cbMaxOp;
754 return True;
755
756 def generateStdTestGregMemSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, auInputs):
757 """ Generate all SIB variations for the given iOp1 (reg) value. """
758 assert cAddrBits in [32, 64];
759 i = oGen.cSibBasePerRun;
760 while i > 0:
761 oGen.iSibBaseReg = (oGen.iSibBaseReg + 1) % oGen.oTarget.getGRegCount(cAddrBits / 8);
762 if oGen.iSibBaseReg == X86_GREG_xSP: # no RSP testing atm.
763 continue;
764
765 j = oGen.getSibIndexPerRun();
766 while j > 0:
767 oGen.iSibIndexReg = (oGen.iSibIndexReg + 1) % oGen.oTarget.getGRegCount(cAddrBits / 8);
768 if oGen.iSibIndexReg == iOp1 and oGen.iSibIndexReg != 4 and cAddrBits != cbMaxOp:
769 continue; # Don't know the high bit of the address ending up the result - skip it for now.
770
771 for iMod in [0, 1, 2]:
772 if oGen.iSibBaseReg == iOp1 \
773 and ((oGen.iSibBaseReg != 5 and oGen.iSibBaseReg != 13) or iMod != 0) \
774 and cAddrBits != cbMaxOp:
775 continue; # Don't know the high bit of the address ending up the result - skip it for now.
776
777 for _ in oGen.oSibScaleRange:
778 oGen.iSibScale *= 2;
779 if oGen.iSibScale > 8:
780 oGen.iSibScale = 1;
781
782 for uInput in auInputs:
783 oGen.newSubTest();
784 uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[iOp1], oGen);
785 self.generateOneStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod,
786 oGen.iSibBaseReg, oGen.iSibIndexReg, oGen.iSibScale,
787 uInput, uResult);
788 j -= 1;
789 i -= 1;
790
791 return True;
792
793
794 def generateStandardTests(self, oGen):
795 """ Generate standard tests. """
796
797 # Parameters.
798 cbDefOp = oGen.oTarget.getDefOpBytes();
799 cbMaxOp = oGen.oTarget.getMaxOpBytes();
800 auShortInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen);
801 auLongInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen, fLong = True);
802 iLongOp1 = oGen.oTarget.randGRegNoSp();
803 iLongOp2 = oGen.oTarget.randGRegNoSp();
804
805 # Register tests
806 if True:
807 for cbEffOp in self.acbOpVars:
808 if cbEffOp > cbMaxOp:
809 continue;
810 oOp2Range = range(oGen.oTarget.getGRegCount(cbEffOp));
811 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
812 oOp2Range = [iLongOp2,];
813 oGen.write('; cbEffOp=%u\n' % (cbEffOp,));
814
815 for iOp1 in range(oGen.oTarget.getGRegCount(cbEffOp)):
816 if iOp1 == X86_GREG_xSP:
817 continue; # Cannot test xSP atm.
818 for iOp2 in oOp2Range:
819 if (iOp2 >= 16 and iOp1 in range(4, 16)) \
820 or (iOp1 >= 16 and iOp2 in range(4, 16)):
821 continue; # Any REX encoding turns AH,CH,DH,BH regs into SPL,BPL,SIL,DIL.
822 if iOp2 == X86_GREG_xSP:
823 continue; # Cannot test xSP atm.
824
825 oGen.write('; iOp2=%u cbEffOp=%u\n' % (iOp2, cbEffOp));
826 for uInput in (auLongInputs if iOp1 == iLongOp1 and iOp2 == iLongOp2 else auShortInputs):
827 oGen.newSubTest();
828 if not oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) and not oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
829 uCur = oGen.auRegValues[iOp1 & 15] if iOp1 != iOp2 else uInput;
830 uResult = self.fnCalcResult(cbEffOp, uInput, uCur, oGen);
831 self.generateOneStdTestGregGreg(oGen, cbEffOp, cbMaxOp, iOp1, iOp1 & 15, iOp2, iOp2 & 15,
832 uInput, uResult);
833 else:
834 self.generateOneStdTestGregGreg8BitHighPain(oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput);
835
836 # Memory test.
837 if True:
838 for cAddrBits in oGen.oTarget.getAddrModes():
839 for cbEffOp in self.acbOpVars:
840 if cbEffOp > cbMaxOp:
841 continue;
842
843 for _ in oGen.getModRegRange(cbEffOp):
844 oGen.iModReg = (oGen.iModReg + 1) % oGen.oTarget.getGRegCount(cbEffOp);
845 if oGen.iModReg == X86_GREG_xSP:
846 continue; # Cannot test xSP atm.
847 if oGen.iModReg > 15:
848 continue; ## TODO AH,CH,DH,BH
849
850 auInputs = auLongInputs if oGen.iModReg == iLongOp1 else auShortInputs;
851 for _ in oGen.oModRmRange:
852 oGen.iModRm = (oGen.iModRm + 1) % oGen.oTarget.getGRegCount(cAddrBits * 8);
853 if oGen.iModRm != 4 or cAddrBits == 16:
854 for uInput in auInputs:
855 oGen.newSubTest();
856 if oGen.iModReg == oGen.iModRm and oGen.iModRm != 5 \
857 and oGen.iModRm != 13 and cbEffOp != cbMaxOp:
858 continue; # Don't know the high bit of the address ending up the result - skip it for now.
859 uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[oGen.iModReg & 15], oGen);
860 self.generateOneStdTestGregMemNoSib(oGen, cAddrBits, cbEffOp, cbMaxOp,
861 oGen.iModReg, oGen.iModRm, uInput, uResult);
862 else:
863 # SIB - currently only short list of inputs or things may get seriously out of hand.
864 self.generateStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, oGen.iModReg, auShortInputs);
865 #break;
866 #break;
867
868
869 return True;
870
871 def generateTest(self, oGen, sTestFnName):
872 oGen.write('VBINSTST_BEGINPROC %s\n' % (sTestFnName,));
873 #oGen.write(' int3\n');
874
875 self.generateStandardTests(oGen);
876
877 #oGen.write(' int3\n');
878 oGen.write(' ret\n');
879 oGen.write('VBINSTST_ENDPROC %s\n' % (sTestFnName,));
880 return True;
881
882
883
884class InstrTest_Mov_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
885 """
886 Tests MOV Gv,Ev.
887 """
888 def __init__(self):
889 InstrTest_MemOrGreg_2_Greg.__init__(self, 'mov Gv,Ev', self.calc_mov);
890
891 @staticmethod
892 def calc_mov(cbEffOp, uInput, uCur, oGen):
893 """ Calculates the result of a mov instruction."""
894 if cbEffOp == 8:
895 return uInput & UINT64_MAX;
896 if cbEffOp == 4:
897 return uInput & UINT32_MAX;
898 if cbEffOp == 2:
899 return (uCur & 0xffffffffffff0000) | (uInput & UINT16_MAX);
900 assert cbEffOp == 1; _ = oGen;
901 return (uCur & 0xffffffffffffff00) | (uInput & UINT8_MAX);
902
903
904class InstrTest_MovSxD_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
905 """
906 Tests MOVSXD Gv,Ev.
907 """
908 def __init__(self):
909 InstrTest_MemOrGreg_2_Greg.__init__(self, 'movsxd Gv,Ev', self.calc_movsxd, acbOpVars = [ 8, 4, 2, ]);
910
911 def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
912 if cbEffOp == 8:
913 oGen.write(' %s %s, %s\n' % (self.sInstr, g_asGRegs64[iOp1], g_asGRegs32[iOp2]));
914 elif cbEffOp == 4 or cbEffOp == 2:
915 abInstr = [];
916 if cbEffOp != oGen.oTarget.getDefOpBytes():
917 abInstr.append(X86_OP_PRF_SIZE_OP);
918 abInstr += calcRexPrefixForTwoModRmRegs(iOp1, iOp2);
919 abInstr.append(0x63);
920 abInstr += calcModRmForTwoRegs(iOp1, iOp2);
921 oGen.writeInstrBytes(abInstr);
922 else:
923 assert False;
924 assert False;
925 return True;
926
927 def isApplicable(self, oGen):
928 return oGen.oTarget.is64Bit();
929
930 @staticmethod
931 def calc_movsxd(cbEffOp, uInput, uCur, oGen):
932 """
933 Calculates the result of a movxsd instruction.
934 Returns the result value (cbMaxOp sized).
935 """
936 _ = oGen;
937 if cbEffOp == 8 and (uInput & RT_BIT_32(31)):
938 return (UINT32_MAX << 32) | (uInput & UINT32_MAX);
939 if cbEffOp == 2:
940 return (uCur & 0xffffffffffff0000) | (uInput & 0xffff);
941 return uInput & UINT32_MAX;
942
943
944class InstrTest_DivIDiv(InstrTestBase):
945 """
946 Tests IDIV and DIV instructions.
947 """
948
949 def __init__(self, fIsIDiv):
950 if not fIsIDiv:
951 InstrTestBase.__init__(self, 'div Gv,Ev', 'div');
952 else:
953 InstrTestBase.__init__(self, 'idiv Gv,Ev', 'idiv');
954 self.fIsIDiv = fIsIDiv;
955
956 def generateInputEdgeCases(self, cbEffOp, fLong, fXcpt):
957 """ Generate edge case inputs for cbEffOp. Returns a list of pairs, dividen + divisor. """
958 # Test params.
959 uStep = 1 << (cbEffOp * 8);
960 if self.fIsIDiv:
961 uStep /= 2;
962
963 # edge tests
964 auRet = [];
965
966 uDivisor = 1 if fLong else 3;
967 uDividend = uStep * uDivisor - 1;
968 for i in range(5 if fLong else 3):
969 auRet.append([uDividend + fXcpt, uDivisor]);
970 if self.fIsIDiv:
971 auRet.append([-uDividend - fXcpt, -uDivisor]);
972 auRet.append([-(uDividend + uDivisor + fXcpt), uDivisor]);
973 auRet.append([ (uDividend + uDivisor + fXcpt), -uDivisor]);
974 if i <= 3 and fLong:
975 auRet.append([uDividend - 1 + fXcpt*3, uDivisor]);
976 if self.fIsIDiv:
977 auRet.append([-(uDividend - 1 + fXcpt*3), -uDivisor]);
978 uDivisor += 1;
979 uDividend += uStep;
980
981 uDivisor = uStep - 1;
982 uDividend = uStep * uDivisor - 1;
983 for _ in range(3 if fLong else 1):
984 auRet.append([uDividend + fXcpt, uDivisor]);
985 if self.fIsIDiv:
986 auRet.append([-uDividend - fXcpt, -uDivisor]);
987 uDivisor -= 1;
988 uDividend -= uStep;
989
990 if self.fIsIDiv:
991 uDivisor = -uStep;
992 for _ in range(3 if fLong else 1):
993 auRet.append([uDivisor * (-uStep - 1) - (not fXcpt), uDivisor]);
994 uDivisor += 1
995 uDivisor = uStep - 1;
996 for _ in range(3 if fLong else 1):
997 auRet.append([-(uDivisor * (uStep + 1) - (not fXcpt)), uDivisor]);
998 uDivisor -= 1
999
1000 return auRet;
1001
1002 def generateInputsNoXcpt(self, cbEffOp, fLong = False):
1003 """ Generate inputs for cbEffOp. Returns a list of pairs, dividen + divisor. """
1004 # Test params.
1005 uStep = 1 << (cbEffOp * 8);
1006 if self.fIsIDiv:
1007 uStep /= 2;
1008
1009 # edge tests
1010 auRet = self.generateInputEdgeCases(cbEffOp, fLong, False)
1011
1012 # random tests.
1013 if self.fIsIDiv:
1014 for _ in range(6 if fLong else 2):
1015 while True:
1016 uDivisor = randSxx(cbEffOp * 8);
1017 if uDivisor == 0 or uDivisor >= uStep or uDivisor < -uStep:
1018 continue;
1019 uDividend = randSxx(cbEffOp * 16);
1020 uResult = uDividend / uDivisor;
1021 if uResult >= uStep or uResult <= -uStep: # exclude difficulties
1022 continue;
1023 break;
1024 auRet.append([uDividend, uDivisor]);
1025 else:
1026 for _ in range(6 if fLong else 2):
1027 while True:
1028 uDivisor = randUxx(cbEffOp * 8);
1029 if uDivisor == 0 or uDivisor >= uStep:
1030 continue;
1031 uDividend = randUxx(cbEffOp * 16);
1032 uResult = uDividend / uDivisor;
1033 if uResult >= uStep:
1034 continue;
1035 break;
1036 auRet.append([uDividend, uDivisor]);
1037
1038 return auRet;
1039
1040 def generateOneStdTestGreg(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1041 """ Generate code of one '[I]DIV rDX:rAX,<GREG>' test. """
1042 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1043 fEffOp = ((1 << (cbEffOp *8) ) - 1);
1044 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1045 fTopOp = fMaxOp - fEffOp;
1046 fFullOp1 = ((1 << (cbEffOp*16)) - 1);
1047
1048 uAX = iDividend & fFullOp1; # full with unsigned
1049 uDX = uAX >> (cbEffOp*8);
1050 uAX &= fEffOp;
1051 uOp2Val = iDivisor & fEffOp;
1052
1053 iQuotient = iDividend / iDivisor;
1054 iReminder = iDividend % iDivisor;
1055 if iReminder != 0 and iQuotient < 0: # python has different rounding rules for negative division.
1056 iQuotient += 1;
1057 iReminder -= iDivisor;
1058 uAXResult = iQuotient & fEffOp;
1059 uDXResult = iReminder & fEffOp;
1060
1061 if cbEffOp < cbMaxOp:
1062 uAX |= randUxx(cbMaxOp * 8) & fTopOp;
1063 uDX |= randUxx(cbMaxOp * 8) & fTopOp;
1064 uOp2Val |= randUxx(cbMaxOp * 8) & fTopOp;
1065 if cbEffOp < 4:
1066 uAXResult |= uAX & fTopOp;
1067 uDXResult |= uDX & fTopOp;
1068 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1069 ' ; iQuotient=%#x (%d) iReminder=%#x (%d)\n'
1070 % ( iDividend & fFullOp1, iDividend, iDivisor & fEffOp, iDivisor,
1071 iQuotient & fEffOp, iQuotient, iReminder & fEffOp, iReminder, ));
1072
1073 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1074 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xDX], uDX,));
1075 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1076 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2], uOp2Val,));
1077
1078 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
1079 oGen.pushConst(uDXResult);
1080 oGen.pushConst(uAXResult);
1081
1082 oGen.write(' %-4s %s\n' % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1083 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, X86_GREG_xDX, iOp2),));
1084 return True;
1085
1086 def generateOneStdTestGreg8Bit(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1087 """ Generate code of one '[I]DIV AX,<GREG>' test (8-bit). """
1088 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1089 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1090 iOp2X = (iOp2 & 3) if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2) else iOp2;
1091 assert iOp2X != X86_GREG_xAX;
1092
1093 uAX = iDividend & UINT16_MAX; # full with unsigned
1094 uOp2Val = iDivisor & UINT8_MAX;
1095
1096 iQuotient = iDividend / iDivisor;
1097 iReminder = iDividend % iDivisor;
1098 if iReminder != 0 and iQuotient < 0: # python has different rounding rules for negative division.
1099 iQuotient += 1;
1100 iReminder -= iDivisor;
1101 uAXResult = (iQuotient & UINT8_MAX) | ((iReminder & UINT8_MAX) << 8);
1102
1103 uAX |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT16_MAX);
1104 uAXResult |= uAX & (fMaxOp - UINT16_MAX);
1105 uOp2Val |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT8_MAX);
1106 if iOp2X != iOp2:
1107 uOp2Val = rotateLeftUxx(cbMaxOp * 8, uOp2Val, 8);
1108 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1109 ' ; iQuotient=%#x (%d) iReminder=%#x (%d)\n'
1110 % ( iDividend & UINT16_MAX, iDividend, iDivisor & UINT8_MAX, iDivisor,
1111 iQuotient & UINT8_MAX, iQuotient, iReminder & UINT8_MAX, iReminder, ));
1112
1113 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1114 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1115 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uOp2Val,));
1116 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
1117 oGen.pushConst(uAXResult);
1118
1119 oGen.write(' %-4s %s\n' % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1120 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, iOp2X),));
1121 return;
1122
1123
1124 def generateStandardTests(self, oGen):
1125 """ Generates test that causes no exceptions. """
1126
1127 # Parameters.
1128 iLongOp2 = oGen.oTarget.randGRegNoSp();
1129
1130 # Register tests
1131 if True:
1132 for cbEffOp in ( 8, 4, 2, 1 ):
1133 if cbEffOp > oGen.oTarget.getMaxOpBytes():
1134 continue;
1135 oGen.write('; cbEffOp=%u\n' % (cbEffOp,));
1136 oOp2Range = range(oGen.oTarget.getGRegCount(cbEffOp));
1137 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
1138 oOp2Range = [iLongOp2,];
1139 for iOp2 in oOp2Range:
1140 if iOp2 == X86_GREG_xSP:
1141 continue; # Cannot test xSP atm.
1142 if iOp2 == X86_GREG_xAX or (cbEffOp > 1 and iOp2 == X86_GREG_xDX):
1143 continue; # Will overflow or be too complicated to get right.
1144 if cbEffOp == 1 and iOp2 == (16 if oGen.oTarget.is64Bit() else 4):
1145 continue; # Avoid dividing by AH, same reasons as above.
1146
1147 for iDividend, iDivisor in self.generateInputsNoXcpt(cbEffOp, iOp2 == iLongOp2):
1148 oGen.newSubTest();
1149 if cbEffOp > 1:
1150 self.generateOneStdTestGreg(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1151 else:
1152 self.generateOneStdTestGreg8Bit(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1153
1154 ## Memory test.
1155 #if False:
1156 # for cAddrBits in oGen.oTarget.getAddrModes():
1157 # for cbEffOp in self.acbOpVars:
1158 # if cbEffOp > cbMaxOp:
1159 # continue;
1160 #
1161 # auInputs = auLongInputs if oGen.iModReg == iLongOp1 else auShortInputs;
1162 # for _ in oGen.oModRmRange:
1163 # oGen.iModRm = (oGen.iModRm + 1) % oGen.oTarget.getGRegCount(cAddrBits * 8);
1164 # if oGen.iModRm != 4 or cAddrBits == 16:
1165 # for uInput in auInputs:
1166 # oGen.newSubTest();
1167 # if oGen.iModReg == oGen.iModRm and oGen.iModRm != 5 and oGen.iModRm != 13 and cbEffOp != cbMaxOp:
1168 # continue; # Don't know the high bit of the address ending up the result - skip it for now.
1169 # uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[oGen.iModReg & 15], oGen);
1170 # self.generateOneStdTestGregMemNoSib(oGen, cAddrBits, cbEffOp, cbMaxOp,
1171 # oGen.iModReg, oGen.iModRm, uInput, uResult);
1172 # else:
1173 # # SIB - currently only short list of inputs or things may get seriously out of hand.
1174 # self.generateStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, oGen.iModReg, auShortInputs);
1175 #
1176 return True;
1177
1178 def generateInputsXcpt(self, cbEffOp, fLong = False):
1179 """
1180 Generate inputs for cbEffOp that will overflow or underflow.
1181 Returns a list of pairs, dividen + divisor.
1182 """
1183 # Test params.
1184 uStep = 1 << (cbEffOp * 8);
1185 if self.fIsIDiv:
1186 uStep /= 2;
1187
1188 # edge tests
1189 auRet = self.generateInputEdgeCases(cbEffOp, fLong, True);
1190 auRet.extend([[0, 0], [1, 0], [ uStep * uStep / 2 - 1, 0]]);
1191
1192 # random tests.
1193 if self.fIsIDiv:
1194 for _ in range(6 if fLong else 2):
1195 while True:
1196 uDivisor = randSxx(cbEffOp * 8);
1197 uDividend = randSxx(cbEffOp * 16);
1198 if uDivisor >= uStep or uDivisor < -uStep:
1199 continue;
1200 if uDivisor != 0:
1201 uResult = uDividend / uDivisor;
1202 if (uResult <= uStep and uResult >= 0) or (uResult >= -uStep and uResult < 0):
1203 continue; # exclude difficulties
1204 break;
1205 auRet.append([uDividend, uDivisor]);
1206 else:
1207 for _ in range(6 if fLong else 2):
1208 while True:
1209 uDivisor = randUxx(cbEffOp * 8);
1210 uDividend = randUxx(cbEffOp * 16);
1211 if uDivisor >= uStep:
1212 continue;
1213 if uDivisor != 0:
1214 uResult = uDividend / uDivisor;
1215 if uResult < uStep:
1216 continue;
1217 break;
1218 auRet.append([uDividend, uDivisor]);
1219
1220 return auRet;
1221
1222 def generateOneDivideErrorTestGreg(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1223 """ Generate code of one '[I]DIV rDX:rAX,<GREG>' test that causes #DE. """
1224 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1225 fEffOp = ((1 << (cbEffOp *8) ) - 1);
1226 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1227 fTopOp = fMaxOp - fEffOp;
1228 fFullOp1 = ((1 << (cbEffOp*16)) - 1);
1229
1230 uAX = iDividend & fFullOp1; # full with unsigned
1231 uDX = uAX >> (cbEffOp*8);
1232 uAX &= fEffOp;
1233 uOp2Val = iDivisor & fEffOp;
1234
1235 if cbEffOp < cbMaxOp:
1236 uAX |= randUxx(cbMaxOp * 8) & fTopOp;
1237 uDX |= randUxx(cbMaxOp * 8) & fTopOp;
1238 uOp2Val |= randUxx(cbMaxOp * 8) & fTopOp;
1239 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1240 % ( iDividend & fFullOp1, iDividend, iDivisor & fEffOp, iDivisor,));
1241 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1242 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xDX], uDX,));
1243 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1244 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2], uOp2Val,));
1245 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
1246 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[X86_GREG_xDX],));
1247 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX],));
1248 oGen.write(' VBINSTST_TRAP_INSTR X86_XCPT_DE, 0, %-4s %s\n'
1249 % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1250 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, X86_GREG_xDX, iOp2),));
1251 return True;
1252
1253 def generateOneDivideErrorTestGreg8Bit(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
1254 """ Generate code of one '[I]DIV AX,<GREG>' test that causes #DE (8-bit). """
1255 if not oGen.oTarget.is64Bit() and iOp2 == 4: # Avoid AH.
1256 iOp2 = 5;
1257
1258 cbMaxOp = oGen.oTarget.getMaxOpBytes();
1259 fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
1260 iOp2X = (iOp2 & 3) if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2) else iOp2;
1261 assert iOp2X != X86_GREG_xAX;
1262
1263 uAX = iDividend & UINT16_MAX; # full with unsigned
1264 uOp2Val = iDivisor & UINT8_MAX;
1265
1266 uAX |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT16_MAX);
1267 uOp2Val |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT8_MAX);
1268 if iOp2X != iOp2:
1269 uOp2Val = rotateLeftUxx(cbMaxOp * 8, uOp2Val, 8);
1270 oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
1271 % ( iDividend & UINT16_MAX, iDividend, iDivisor & UINT8_MAX, iDivisor,));
1272 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
1273 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
1274 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uOp2Val,));
1275 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
1276 oGen.write(' push sAX\n');
1277 oGen.write(' VBINSTST_TRAP_INSTR X86_XCPT_DE, 0, %-4s %s\n'
1278 % (self.sInstr, oGen.gregNameBytes(iOp2, cbEffOp),));
1279 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, iOp2X),));
1280 return;
1281
1282 def generateDivideErrorTests(self, oGen):
1283 """ Generate divide error tests (raises X86_XCPT_DE). """
1284 oGen.write('%ifdef VBINSTST_CAN_DO_TRAPS\n');
1285
1286 # We do one register variation here, assuming the standard test has got them covered.
1287 # Register tests
1288 if True:
1289 iOp2 = oGen.oTarget.randGRegNoSp();
1290 while iOp2 == X86_GREG_xAX or iOp2 == X86_GREG_xDX:
1291 iOp2 = oGen.oTarget.randGRegNoSp();
1292
1293 for cbEffOp in ( 8, 4, 2, 1 ):
1294 if cbEffOp > oGen.oTarget.getMaxOpBytes():
1295 continue;
1296 oGen.write('; cbEffOp=%u iOp2=%u\n' % (cbEffOp, iOp2,));
1297
1298 for iDividend, iDivisor in self.generateInputsXcpt(cbEffOp, fLong = not oGen.isTiny()):
1299 oGen.newSubTest();
1300 if cbEffOp > 1:
1301 self.generateOneDivideErrorTestGreg(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1302 else:
1303 self.generateOneDivideErrorTestGreg8Bit(oGen, cbEffOp, iOp2, iDividend, iDivisor);
1304
1305 oGen.write('%endif ; VBINSTST_CAN_DO_TRAPS\n');
1306 return True;
1307
1308
1309 def generateTest(self, oGen, sTestFnName):
1310 oGen.write('VBINSTST_BEGINPROC %s\n' % (sTestFnName,));
1311 #oGen.write(' int3\n');
1312
1313 self.generateStandardTests(oGen);
1314 self.generateDivideErrorTests(oGen);
1315
1316 #oGen.write(' int3\n');
1317 oGen.write(' ret\n');
1318 oGen.write('VBINSTST_ENDPROC %s\n' % (sTestFnName,));
1319 return True;
1320
1321
1322
1323
1324##
1325# Instruction Tests.
1326#
1327g_aoInstructionTests = [
1328 #InstrTest_Mov_Gv_Ev(),
1329 ##InstrTest_MovSxD_Gv_Ev(),
1330 InstrTest_DivIDiv(fIsIDiv = False),
1331 InstrTest_DivIDiv(fIsIDiv = True),
1332];
1333
1334
1335
1336
1337
1338class InstructionTestGen(object): # pylint: disable=R0902
1339 """
1340 Instruction Test Generator.
1341 """
1342
1343 ## @name Test size
1344 ## @{
1345 ksTestSize_Large = 'large';
1346 ksTestSize_Medium = 'medium';
1347 ksTestSize_Tiny = 'tiny';
1348 ## @}
1349 kasTestSizes = ( ksTestSize_Large, ksTestSize_Medium, ksTestSize_Tiny );
1350
1351
1352
1353 def __init__(self, oOptions):
1354 self.oOptions = oOptions;
1355 self.oTarget = g_dTargetEnvs[oOptions.sTargetEnv];
1356
1357 # Calculate the number of output files.
1358 self.cFiles = 1;
1359 if len(g_aoInstructionTests) > self.oOptions.cInstrPerFile:
1360 self.cFiles = len(g_aoInstructionTests) / self.oOptions.cInstrPerFile;
1361 if self.cFiles * self.oOptions.cInstrPerFile < len(g_aoInstructionTests):
1362 self.cFiles += 1;
1363
1364 # Fix the known register values.
1365 self.au64Regs = randUxxList(64, 16);
1366 self.au32Regs = [(self.au64Regs[i] & UINT32_MAX) for i in range(8)];
1367 self.au16Regs = [(self.au64Regs[i] & UINT16_MAX) for i in range(8)];
1368 self.auRegValues = self.au64Regs if self.oTarget.is64Bit() else self.au32Regs;
1369
1370 # Declare state variables used while generating.
1371 self.oFile = sys.stderr;
1372 self.iFile = -1;
1373 self.sFile = '';
1374 self._dCheckFns = dict();
1375 self._dMemSetupFns = dict();
1376 self._d64BitConsts = dict();
1377
1378 # State variables used while generating test convenientely placed here (lazy bird)...
1379 self.iModReg = 0;
1380 self.iModRm = 0;
1381 self.iSibBaseReg = 0;
1382 self.iSibIndexReg = 0;
1383 self.iSibScale = 1;
1384 if self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
1385 self._oModRegRange = range(2);
1386 self._oModRegRange8 = range(2);
1387 self.oModRmRange = range(2);
1388 self.cSibBasePerRun = 1;
1389 self._cSibIndexPerRun = 2;
1390 self.oSibScaleRange = range(1);
1391 elif self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
1392 self._oModRegRange = range( 5 if self.oTarget.is64Bit() else 4);
1393 self._oModRegRange8 = range( 6 if self.oTarget.is64Bit() else 4);
1394 self.oModRmRange = range(5);
1395 self.cSibBasePerRun = 5;
1396 self._cSibIndexPerRun = 4
1397 self.oSibScaleRange = range(2);
1398 else:
1399 self._oModRegRange = range(16 if self.oTarget.is64Bit() else 8);
1400 self._oModRegRange8 = range(20 if self.oTarget.is64Bit() else 8);
1401 self.oModRmRange = range(16 if self.oTarget.is64Bit() else 8);
1402 self.cSibBasePerRun = 8;
1403 self._cSibIndexPerRun = 9;
1404 self.oSibScaleRange = range(4);
1405 self.iSibIndexRange = 0;
1406
1407
1408 #
1409 # Methods used by instruction tests.
1410 #
1411
1412 def write(self, sText):
1413 """ Writes to the current output file. """
1414 return self.oFile.write(unicode(sText));
1415
1416 def writeln(self, sText):
1417 """ Writes a line to the current output file. """
1418 self.write(sText);
1419 return self.write('\n');
1420
1421 def writeInstrBytes(self, abInstr):
1422 """
1423 Emits an instruction given as a sequence of bytes values.
1424 """
1425 self.write(' db %#04x' % (abInstr[0],));
1426 for i in range(1, len(abInstr)):
1427 self.write(', %#04x' % (abInstr[i],));
1428 return self.write('\n');
1429
1430 def newSubTest(self):
1431 """
1432 Indicates that a new subtest has started.
1433 """
1434 self.write(' mov dword [VBINSTST_NAME(g_uVBInsTstSubTestIndicator) xWrtRIP], __LINE__\n');
1435 return True;
1436
1437 def needGRegChecker(self, iReg1, iReg2 = None, iReg3 = None):
1438 """
1439 Records the need for a given register checker function, returning its label.
1440 """
1441 if iReg2 is not None:
1442 if iReg3 is not None:
1443 sName = '%s_%s_%s' % (self.oTarget.asGRegs[iReg1], self.oTarget.asGRegs[iReg2], self.oTarget.asGRegs[iReg3],);
1444 else:
1445 sName = '%s_%s' % (self.oTarget.asGRegs[iReg1], self.oTarget.asGRegs[iReg2],);
1446 else:
1447 sName = '%s' % (self.oTarget.asGRegs[iReg1],);
1448 assert iReg3 is None;
1449
1450 if sName in self._dCheckFns:
1451 self._dCheckFns[sName] += 1;
1452 else:
1453 self._dCheckFns[sName] = 1;
1454
1455 return 'Common_Check_' + sName;
1456
1457 def needGRegMemSetup(self, cAddrBits, cbEffOp, iBaseReg = None, offDisp = None, iIndexReg = None, iScale = 1):
1458 """
1459 Records the need for a given register checker function, returning its label.
1460 """
1461 assert cAddrBits in [64, 32, 16];
1462 assert cbEffOp in [8, 4, 2, 1];
1463 assert iScale in [1, 2, 4, 8];
1464
1465 sName = '%ubit_U%u' % (cAddrBits, cbEffOp * 8,);
1466 if iBaseReg is not None:
1467 sName += '_%s' % (gregName(iBaseReg, cAddrBits),);
1468 sName += '_x%u' % (iScale,);
1469 if iIndexReg is not None:
1470 sName += '_%s' % (gregName(iIndexReg, cAddrBits),);
1471 if offDisp is not None:
1472 sName += '_%#010x' % (offDisp & UINT32_MAX, );
1473 if sName in self._dMemSetupFns:
1474 self._dMemSetupFns[sName] += 1;
1475 else:
1476 self._dMemSetupFns[sName] = 1;
1477 return 'Common_MemSetup_' + sName;
1478
1479 def need64BitConstant(self, uVal):
1480 """
1481 Records the need for a 64-bit constant, returning its label.
1482 These constants are pooled to attempt reduce the size of the whole thing.
1483 """
1484 assert uVal >= 0 and uVal <= UINT64_MAX;
1485 if uVal in self._d64BitConsts:
1486 self._d64BitConsts[uVal] += 1;
1487 else:
1488 self._d64BitConsts[uVal] = 1;
1489 return 'g_u64Const_0x%016x' % (uVal, );
1490
1491 def pushConst(self, uResult):
1492 """
1493 Emits a push constant value, taking care of high values on 64-bit hosts.
1494 """
1495 if self.oTarget.is64Bit() and uResult >= 0x80000000:
1496 self.write(' push qword [%s wrt rip]\n' % (self.need64BitConstant(uResult),));
1497 else:
1498 self.write(' push dword 0x%x\n' % (uResult,));
1499 return True;
1500
1501 def getDispForMod(self, iMod, cbAlignment = 1):
1502 """
1503 Get a set of address dispositions for a given addressing mode.
1504 The alignment restriction is for SIB scaling.
1505 """
1506 assert cbAlignment in [1, 2, 4, 8];
1507 if iMod == 0:
1508 aoffDisp = [ None, ];
1509 elif iMod == 1:
1510 aoffDisp = [ 127 & ~(cbAlignment - 1), -128 ];
1511 elif iMod == 2:
1512 aoffDisp = [ 2147483647 & ~(cbAlignment - 1), -2147483648 ];
1513 else: assert False;
1514 return aoffDisp;
1515
1516 def getModRegRange(self, cbEffOp):
1517 """
1518 The Mod R/M register range varies with the effective operand size, for
1519 8-bit registers we have 4 more.
1520 """
1521 if cbEffOp == 1:
1522 return self._oModRegRange8;
1523 return self._oModRegRange;
1524
1525 def getSibIndexPerRun(self):
1526 """
1527 We vary the SIB index test range a little to try cover more operand
1528 combinations and avoid repeating the same ones.
1529 """
1530 self.iSibIndexRange += 1;
1531 self.iSibIndexRange %= 3;
1532 if self.iSibIndexRange == 0:
1533 return self._cSibIndexPerRun - 1;
1534 return self._cSibIndexPerRun;
1535
1536 def isTiny(self):
1537 """ Checks if we're in tiny mode."""
1538 return self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny;
1539
1540
1541 #
1542 # Forwarding calls for oTarget to shorted typing and lessen the attacks
1543 # on the right margin.
1544 #
1545
1546 def gregNameBits(self, iReg, cBitsWide):
1547 """ Target: Get the name of a general register for the given size (in bits). """
1548 return self.oTarget.gregNameBits(iReg, cBitsWide);
1549
1550 def gregNameBytes(self, iReg, cbWide):
1551 """ Target: Get the name of a general register for the given size (in bytes). """
1552 return self.oTarget.gregNameBytes(iReg, cbWide);
1553
1554 def is64Bit(self):
1555 """ Target: Is the target 64-bit? """
1556 return self.oTarget.is64Bit();
1557
1558
1559 #
1560 # Internal machinery.
1561 #
1562
1563 def _randInitIndexes(self):
1564 """
1565 Initializes the Mod R/M and SIB state index with random numbers prior
1566 to generating a test.
1567
1568 Note! As with all other randomness and variations we do, we cannot
1569 test all combinations for each and every instruction so we try
1570 get coverage over time.
1571 """
1572 self.iModReg = randU8();
1573 self.iModRm = randU8();
1574 self.iSibBaseReg = randU8();
1575 self.iSibIndexReg = randU8();
1576 self.iSibScale = 1 << (randU8() & 3);
1577 self.iSibIndexRange = randU8();
1578 return True;
1579
1580 def _calcTestFunctionName(self, oInstrTest, iInstrTest):
1581 """
1582 Calc a test function name for the given instruction test.
1583 """
1584 sName = 'TestInstr%03u_%s' % (iInstrTest, oInstrTest.sName);
1585 return sName.replace(',', '_').replace(' ', '_').replace('%', '_');
1586
1587 def _generateFileHeader(self, ):
1588 """
1589 Writes the file header.
1590 Raises exception on trouble.
1591 """
1592 self.write('; $Id: InstructionTestGen.py 47139 2013-07-14 19:54:23Z vboxsync $\n'
1593 ';; @file %s\n'
1594 '; Autogenerate by %s %s. DO NOT EDIT\n'
1595 ';\n'
1596 '\n'
1597 ';\n'
1598 '; Headers\n'
1599 ';\n'
1600 '%%include "env-%s.mac"\n'
1601 % ( os.path.basename(self.sFile),
1602 os.path.basename(__file__), __version__[11:-1],
1603 self.oTarget.sName,
1604 ) );
1605 # Target environment specific init stuff.
1606
1607 #
1608 # Global variables.
1609 #
1610 self.write('\n\n'
1611 ';\n'
1612 '; Globals\n'
1613 ';\n');
1614 self.write('VBINSTST_BEGINDATA\n'
1615 'VBINSTST_GLOBALNAME_EX g_pvLow16Mem4K, data hidden\n'
1616 ' dq 0\n'
1617 'VBINSTST_GLOBALNAME_EX g_pvLow32Mem4K, data hidden\n'
1618 ' dq 0\n'
1619 'VBINSTST_GLOBALNAME_EX g_pvMem4K, data hidden\n'
1620 ' dq 0\n'
1621 'VBINSTST_GLOBALNAME_EX g_uVBInsTstSubTestIndicator, data hidden\n'
1622 ' dd 0\n'
1623 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
1624 'VBINSTST_TRAP_RECS_BEGIN\n'
1625 '%endif\n'
1626 'VBINSTST_BEGINCODE\n'
1627 );
1628 self.write('%ifdef RT_ARCH_AMD64\n');
1629 for i in range(len(g_asGRegs64)):
1630 self.write('g_u64KnownValue_%s: dq 0x%x\n' % (g_asGRegs64[i], self.au64Regs[i]));
1631 self.write('%endif\n\n')
1632
1633 #
1634 # Common functions.
1635 #
1636
1637 # Loading common values.
1638 self.write('\n\n'
1639 'VBINSTST_BEGINPROC Common_LoadKnownValues\n'
1640 '%ifdef RT_ARCH_AMD64\n');
1641 for i in range(len(g_asGRegs64NoSp)):
1642 if g_asGRegs64NoSp[i]:
1643 self.write(' mov %s, 0x%x\n' % (g_asGRegs64NoSp[i], self.au64Regs[i],));
1644 self.write('%else\n');
1645 for i in range(8):
1646 if g_asGRegs32NoSp[i]:
1647 self.write(' mov %s, 0x%x\n' % (g_asGRegs32NoSp[i], self.au32Regs[i],));
1648 self.write('%endif\n'
1649 ' ret\n'
1650 'VBINSTST_ENDPROC Common_LoadKnownValues\n'
1651 '\n');
1652
1653 self.write('VBINSTST_BEGINPROC Common_CheckKnownValues\n'
1654 '%ifdef RT_ARCH_AMD64\n');
1655 for i in range(len(g_asGRegs64NoSp)):
1656 if g_asGRegs64NoSp[i]:
1657 self.write(' cmp %s, [g_u64KnownValue_%s wrt rip]\n'
1658 ' je .ok_%u\n'
1659 ' push %u ; register number\n'
1660 ' push %s ; actual\n'
1661 ' push qword [g_u64KnownValue_%s wrt rip] ; expected\n'
1662 ' call VBINSTST_NAME(Common_BadValue)\n'
1663 '.ok_%u:\n'
1664 % ( g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i, i, g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i,));
1665 self.write('%else\n');
1666 for i in range(8):
1667 if g_asGRegs32NoSp[i]:
1668 self.write(' cmp %s, 0x%x\n'
1669 ' je .ok_%u\n'
1670 ' push %u ; register number\n'
1671 ' push %s ; actual\n'
1672 ' push dword 0x%x ; expected\n'
1673 ' call VBINSTST_NAME(Common_BadValue)\n'
1674 '.ok_%u:\n'
1675 % ( g_asGRegs32NoSp[i], self.au32Regs[i], i, i, g_asGRegs32NoSp[i], self.au32Regs[i], i,));
1676 self.write('%endif\n'
1677 ' ret\n'
1678 'VBINSTST_ENDPROC Common_CheckKnownValues\n'
1679 '\n');
1680
1681 return True;
1682
1683 def _generateMemSetupFunctions(self): # pylint: disable=R0915
1684 """
1685 Generates the memory setup functions.
1686 """
1687 cDefAddrBits = self.oTarget.getDefAddrBits();
1688 for sName in self._dMemSetupFns:
1689 # Unpack it.
1690 asParams = sName.split('_');
1691 cAddrBits = int(asParams[0][:-3]); assert asParams[0][-3:] == 'bit';
1692 cEffOpBits = int(asParams[1][1:]); assert asParams[1][0] == 'U';
1693 if cAddrBits == 64: asAddrGRegs = g_asGRegs64;
1694 elif cAddrBits == 32: asAddrGRegs = g_asGRegs32;
1695 else: asAddrGRegs = g_asGRegs16;
1696
1697 i = 2;
1698 iBaseReg = None;
1699 sBaseReg = None;
1700 if i < len(asParams) and asParams[i] in asAddrGRegs:
1701 sBaseReg = asParams[i];
1702 iBaseReg = asAddrGRegs.index(sBaseReg);
1703 i += 1
1704
1705 assert i < len(asParams); assert asParams[i][0] == 'x';
1706 iScale = iScale = int(asParams[i][1:]); assert iScale in [1, 2, 4, 8], '%u %s' % (iScale, sName);
1707 i += 1;
1708
1709 sIndexReg = None;
1710 iIndexReg = None;
1711 if i < len(asParams) and asParams[i] in asAddrGRegs:
1712 sIndexReg = asParams[i];
1713 iIndexReg = asAddrGRegs.index(sIndexReg);
1714 i += 1;
1715
1716 u32Disp = None;
1717 if i < len(asParams) and len(asParams[i]) == 10:
1718 u32Disp = long(asParams[i], 16);
1719 i += 1;
1720
1721 assert i == len(asParams), 'i=%d len=%d len[i]=%d (%s)' % (i, len(asParams), len(asParams[i]), asParams[i],);
1722 assert iScale == 1 or iIndexReg is not None;
1723
1724 # Find a temporary register.
1725 iTmpReg1 = X86_GREG_xCX;
1726 while iTmpReg1 in [iBaseReg, iIndexReg]:
1727 iTmpReg1 += 1;
1728
1729 # Prologue.
1730 self.write('\n\n'
1731 '; cAddrBits=%s cEffOpBits=%s iBaseReg=%s u32Disp=%s iIndexReg=%s iScale=%s\n'
1732 'VBINSTST_BEGINPROC Common_MemSetup_%s\n'
1733 ' MY_PUSH_FLAGS\n'
1734 ' push %s\n'
1735 % ( cAddrBits, cEffOpBits, iBaseReg, u32Disp, iIndexReg, iScale,
1736 sName, self.oTarget.asGRegs[iTmpReg1], ));
1737
1738 # Figure out what to use.
1739 if cEffOpBits == 64:
1740 sTmpReg1 = g_asGRegs64[iTmpReg1];
1741 sDataVar = 'VBINSTST_NAME(g_u64Data)';
1742 elif cEffOpBits == 32:
1743 sTmpReg1 = g_asGRegs32[iTmpReg1];
1744 sDataVar = 'VBINSTST_NAME(g_u32Data)';
1745 elif cEffOpBits == 16:
1746 sTmpReg1 = g_asGRegs16[iTmpReg1];
1747 sDataVar = 'VBINSTST_NAME(g_u16Data)';
1748 else:
1749 assert cEffOpBits == 8; assert iTmpReg1 < 4;
1750 sTmpReg1 = g_asGRegs8Rex[iTmpReg1];
1751 sDataVar = 'VBINSTST_NAME(g_u8Data)';
1752
1753 # Special case: reg + reg * [2,4,8]
1754 if iBaseReg == iIndexReg and iBaseReg is not None and iScale != 1:
1755 iTmpReg2 = X86_GREG_xBP;
1756 while iTmpReg2 in [iBaseReg, iIndexReg, iTmpReg1]:
1757 iTmpReg2 += 1;
1758 sTmpReg2 = gregName(iTmpReg2, cAddrBits);
1759 self.write(' push sAX\n'
1760 ' push %s\n'
1761 ' push sDX\n'
1762 % (self.oTarget.asGRegs[iTmpReg2],));
1763 if cAddrBits == 16:
1764 self.write(' mov %s, [VBINSTST_NAME(g_pvLow16Mem4K) xWrtRIP]\n' % (sTmpReg2,));
1765 else:
1766 self.write(' mov %s, [VBINSTST_NAME(g_pvLow32Mem4K) xWrtRIP]\n' % (sTmpReg2,));
1767 self.write(' add %s, 0x200\n' % (sTmpReg2,));
1768 self.write(' mov %s, %s\n' % (gregName(X86_GREG_xAX, cAddrBits), sTmpReg2,));
1769 if u32Disp is not None:
1770 self.write(' sub %s, %d\n' % ( gregName(X86_GREG_xAX, cAddrBits), convU32ToSigned(u32Disp), ));
1771 self.write(' xor edx, edx\n'
1772 '%if xCB == 2\n'
1773 ' push 0\n'
1774 '%endif\n');
1775 self.write(' push %u\n' % (iScale + 1,));
1776 self.write(' div %s [xSP]\n' % ('qword' if cAddrBits == 64 else 'dword',));
1777 self.write(' sub %s, %s\n' % (sTmpReg2, gregName(X86_GREG_xDX, cAddrBits),));
1778 self.write(' pop sDX\n'
1779 ' pop sDX\n'); # sTmpReg2 is eff address; sAX is sIndexReg value.
1780 # Note! sTmpReg1 can be xDX and that's no problem now.
1781 self.write(' mov %s, [xSP + sCB*3 + MY_PUSH_FLAGS_SIZE + xCB]\n' % (sTmpReg1,));
1782 self.write(' mov [%s], %s\n' % (sTmpReg2, sTmpReg1,)); # Value in place.
1783 self.write(' pop %s\n' % (self.oTarget.asGRegs[iTmpReg2],));
1784 if iBaseReg == X86_GREG_xAX:
1785 self.write(' pop %s\n' % (self.oTarget.asGRegs[iTmpReg1],));
1786 else:
1787 self.write(' mov %s, %s\n' % (sBaseReg, gregName(X86_GREG_xAX, cAddrBits),));
1788 self.write(' pop sAX\n');
1789
1790 else:
1791 # Load the value and mem address, storing the value there.
1792 # Note! ASSUMES that the scale and disposition works fine together.
1793 sAddrReg = sBaseReg if sBaseReg is not None else sIndexReg;
1794 self.write(' mov %s, [xSP + sCB + MY_PUSH_FLAGS_SIZE + xCB]\n' % (sTmpReg1,));
1795 if cAddrBits >= cDefAddrBits:
1796 self.write(' mov [%s xWrtRIP], %s\n' % (sDataVar, sTmpReg1,));
1797 self.write(' lea %s, [%s xWrtRIP]\n' % (sAddrReg, sDataVar,));
1798 else:
1799 if cAddrBits == 16:
1800 self.write(' mov %s, [VBINSTST_NAME(g_pvLow16Mem4K) xWrtRIP]\n' % (sAddrReg,));
1801 else:
1802 self.write(' mov %s, [VBINSTST_NAME(g_pvLow32Mem4K) xWrtRIP]\n' % (sAddrReg,));
1803 self.write(' add %s, %s\n' % (sAddrReg, (randU16() << cEffOpBits) & 0xfff, ));
1804 self.write(' mov [%s], %s\n' % (sAddrReg, sTmpReg1, ));
1805
1806 # Adjust for disposition and scaling.
1807 if u32Disp is not None:
1808 self.write(' sub %s, %d\n' % ( sAddrReg, convU32ToSigned(u32Disp), ));
1809 if iIndexReg is not None:
1810 if iBaseReg == iIndexReg:
1811 assert iScale == 1;
1812 assert u32Disp is None or (u32Disp & 1) == 0;
1813 self.write(' shr %s, 1\n' % (sIndexReg,));
1814 elif sBaseReg is not None:
1815 uIdxRegVal = randUxx(cAddrBits);
1816 if cAddrBits == 64:
1817 self.write(' mov %s, %u\n'
1818 ' sub %s, %s\n'
1819 ' mov %s, %u\n'
1820 % ( sIndexReg, (uIdxRegVal * iScale) & UINT64_MAX,
1821 sBaseReg, sIndexReg,
1822 sIndexReg, uIdxRegVal, ));
1823 else:
1824 assert cAddrBits == 32;
1825 self.write(' mov %s, %u\n'
1826 ' sub %s, %#06x\n'
1827 % ( sIndexReg, uIdxRegVal, sBaseReg, (uIdxRegVal * iScale) & UINT32_MAX, ));
1828 elif iScale == 2:
1829 assert u32Disp is None or (u32Disp & 1) == 0;
1830 self.write(' shr %s, 1\n' % (sIndexReg,));
1831 elif iScale == 4:
1832 assert u32Disp is None or (u32Disp & 3) == 0;
1833 self.write(' shr %s, 2\n' % (sIndexReg,));
1834 elif iScale == 8:
1835 assert u32Disp is None or (u32Disp & 7) == 0;
1836 self.write(' shr %s, 3\n' % (sIndexReg,));
1837 else:
1838 assert iScale == 1;
1839
1840 # Set upper bits that's supposed to be unused.
1841 if cDefAddrBits > cAddrBits or cAddrBits == 16:
1842 if cDefAddrBits == 64:
1843 assert cAddrBits == 32;
1844 if iBaseReg is not None:
1845 self.write(' mov %s, %#018x\n'
1846 ' or %s, %s\n'
1847 % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
1848 g_asGRegs64[iBaseReg], g_asGRegs64[iTmpReg1],));
1849 if iIndexReg is not None and iIndexReg != iBaseReg:
1850 self.write(' mov %s, %#018x\n'
1851 ' or %s, %s\n'
1852 % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
1853 g_asGRegs64[iIndexReg], g_asGRegs64[iTmpReg1],));
1854 else:
1855 assert cDefAddrBits == 32; assert cAddrBits == 16; assert iIndexReg is None;
1856 if iBaseReg is not None:
1857 self.write(' or %s, %#010x\n'
1858 % ( g_asGRegs32[iBaseReg], randU32() & 0xffff0000, ));
1859
1860 # Epilogue.
1861 self.write(' pop %s\n'
1862 ' MY_POP_FLAGS\n'
1863 ' ret sCB\n'
1864 'VBINSTST_ENDPROC Common_MemSetup_%s\n'
1865 % ( self.oTarget.asGRegs[iTmpReg1], sName,));
1866
1867
1868 def _generateFileFooter(self):
1869 """
1870 Generates file footer.
1871 """
1872
1873 # Terminate the trap records.
1874 self.write('\n\n'
1875 ';\n'
1876 '; Terminate the trap records\n'
1877 ';\n'
1878 'VBINSTST_BEGINDATA\n'
1879 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
1880 'VBINSTST_TRAP_RECS_END\n'
1881 '%endif\n'
1882 'VBINSTST_BEGINCODE\n');
1883
1884 # Register checking functions.
1885 for sName in self._dCheckFns:
1886 asRegs = sName.split('_');
1887 sPushSize = 'dword';
1888
1889 # Prologue
1890 self.write('\n\n'
1891 '; Checks 1 or more register values, expected values pushed on the stack.\n'
1892 '; To save space, the callee cleans up the stack.'
1893 '; Ref count: %u\n'
1894 'VBINSTST_BEGINPROC Common_Check_%s\n'
1895 ' MY_PUSH_FLAGS\n'
1896 % ( self._dCheckFns[sName], sName, ) );
1897
1898 # Register checks.
1899 for i in range(len(asRegs)):
1900 sReg = asRegs[i];
1901 iReg = self.oTarget.asGRegs.index(sReg);
1902 if i == asRegs.index(sReg): # Only check once, i.e. input = output reg.
1903 self.write(' cmp %s, [xSP + MY_PUSH_FLAGS_SIZE + xCB + sCB * %u]\n'
1904 ' je .equal%u\n'
1905 ' push %s %u ; register number\n'
1906 ' push %s ; actual\n'
1907 ' mov %s, [xSP + sCB*2 + MY_PUSH_FLAGS_SIZE + xCB + sCB * %u]\n'
1908 ' push %s ; expected\n'
1909 ' call VBINSTST_NAME(Common_BadValue)\n'
1910 '.equal%u:\n'
1911 % ( sReg, i, i, sPushSize, iReg, sReg, sReg, i, sReg, i, ) );
1912
1913
1914 # Restore known register values and check the other registers.
1915 for sReg in asRegs:
1916 if self.oTarget.is64Bit():
1917 self.write(' mov %s, [g_u64KnownValue_%s wrt rip]\n' % (sReg, sReg,));
1918 else:
1919 iReg = self.oTarget.asGRegs.index(sReg)
1920 self.write(' mov %s, 0x%x\n' % (sReg, self.au32Regs[iReg],));
1921 self.write(' MY_POP_FLAGS\n'
1922 ' call VBINSTST_NAME(Common_CheckKnownValues)\n'
1923 ' ret sCB*%u\n'
1924 'VBINSTST_ENDPROC Common_Check_%s\n'
1925 % (len(asRegs), sName,));
1926
1927 # memory setup functions
1928 self._generateMemSetupFunctions();
1929
1930 # 64-bit constants.
1931 if len(self._d64BitConsts) > 0:
1932 self.write('\n\n'
1933 ';\n'
1934 '; 64-bit constants\n'
1935 ';\n');
1936 for uVal in self._d64BitConsts:
1937 self.write('g_u64Const_0x%016x: dq 0x%016x ; Ref count: %d\n' % (uVal, uVal, self._d64BitConsts[uVal], ) );
1938
1939 return True;
1940
1941 def _generateTests(self):
1942 """
1943 Generate the test cases.
1944 """
1945 for self.iFile in range(self.cFiles):
1946 if self.cFiles == 1:
1947 self.sFile = '%s.asm' % (self.oOptions.sOutputBase,)
1948 else:
1949 self.sFile = '%s-%u.asm' % (self.oOptions.sOutputBase, self.iFile)
1950 self.oFile = sys.stdout;
1951 if self.oOptions.sOutputBase != '-':
1952 self.oFile = io.open(self.sFile, 'w', buffering = 65536, encoding = 'utf-8');
1953
1954 self._generateFileHeader();
1955
1956 # Calc the range.
1957 iInstrTestStart = self.iFile * self.oOptions.cInstrPerFile;
1958 iInstrTestEnd = iInstrTestStart + self.oOptions.cInstrPerFile;
1959 if iInstrTestEnd > len(g_aoInstructionTests):
1960 iInstrTestEnd = len(g_aoInstructionTests);
1961
1962 # Generate the instruction tests.
1963 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1964 oInstrTest = g_aoInstructionTests[iInstrTest];
1965 self.write('\n'
1966 '\n'
1967 ';\n'
1968 '; %s\n'
1969 ';\n'
1970 % (oInstrTest.sName,));
1971 self._randInitIndexes();
1972 oInstrTest.generateTest(self, self._calcTestFunctionName(oInstrTest, iInstrTest));
1973
1974 # Generate the main function.
1975 self.write('\n\n'
1976 'VBINSTST_BEGINPROC TestInstrMain\n'
1977 ' MY_PUSH_ALL\n'
1978 ' sub xSP, 40h\n'
1979 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
1980 ' VBINSTST_TRAP_RECS_INSTALL\n'
1981 '%endif\n'
1982 '\n');
1983
1984 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1985 oInstrTest = g_aoInstructionTests[iInstrTest];
1986 if oInstrTest.isApplicable(self):
1987 self.write('%%ifdef ASM_CALL64_GCC\n'
1988 ' lea rdi, [.szInstr%03u wrt rip]\n'
1989 '%%elifdef ASM_CALL64_MSC\n'
1990 ' lea rcx, [.szInstr%03u wrt rip]\n'
1991 '%%else\n'
1992 ' mov xAX, .szInstr%03u\n'
1993 ' mov [xSP], xAX\n'
1994 '%%endif\n'
1995 ' VBINSTST_CALL_FN_SUB_TEST\n'
1996 ' call VBINSTST_NAME(%s)\n'
1997 % ( iInstrTest, iInstrTest, iInstrTest, self._calcTestFunctionName(oInstrTest, iInstrTest)));
1998
1999 self.write('\n'
2000 '%ifdef VBINSTST_CAN_DO_TRAPS\n'
2001 ' VBINSTST_TRAP_RECS_UNINSTALL\n'
2002 '%endif\n'
2003 ' add xSP, 40h\n'
2004 ' MY_POP_ALL\n'
2005 ' ret\n\n');
2006 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
2007 self.write('.szInstr%03u: db \'%s\', 0\n' % (iInstrTest, g_aoInstructionTests[iInstrTest].sName,));
2008 self.write('VBINSTST_ENDPROC TestInstrMain\n\n');
2009
2010 self._generateFileFooter();
2011 if self.oOptions.sOutputBase != '-':
2012 self.oFile.close();
2013 self.oFile = None;
2014 self.sFile = '';
2015
2016 return RTEXITCODE_SUCCESS;
2017
2018 def _runMakefileMode(self):
2019 """
2020 Generate a list of output files on standard output.
2021 """
2022 if self.cFiles == 1:
2023 print('%s.asm' % (self.oOptions.sOutputBase,));
2024 else:
2025 print(' '.join('%s-%s.asm' % (self.oOptions.sOutputBase, i) for i in range(self.cFiles)));
2026 return RTEXITCODE_SUCCESS;
2027
2028 def run(self):
2029 """
2030 Generates the tests or whatever is required.
2031 """
2032 if self.oOptions.fMakefileMode:
2033 return self._runMakefileMode();
2034 sys.stderr.write('InstructionTestGen.py: Seed = %s\n' % (g_iMyRandSeed,));
2035 return self._generateTests();
2036
2037 @staticmethod
2038 def main():
2039 """
2040 Main function a la C/C++. Returns exit code.
2041 """
2042
2043 #
2044 # Parse the command line.
2045 #
2046 oParser = OptionParser(version = __version__[11:-1].strip());
2047 oParser.add_option('--makefile-mode', dest = 'fMakefileMode', action = 'store_true', default = False,
2048 help = 'Special mode for use to output a list of output files for the benefit of '
2049 'the make program (kmk).');
2050 oParser.add_option('--split', dest = 'cInstrPerFile', metavar = '<instr-per-file>', type = 'int', default = 9999999,
2051 help = 'Number of instruction to test per output file.');
2052 oParser.add_option('--output-base', dest = 'sOutputBase', metavar = '<file>', default = None,
2053 help = 'The output file base name, no suffix please. Required.');
2054 oParser.add_option('--target', dest = 'sTargetEnv', metavar = '<target>',
2055 default = 'iprt-r3-32',
2056 choices = g_dTargetEnvs.keys(),
2057 help = 'The target environment. Choices: %s'
2058 % (', '.join(sorted(g_dTargetEnvs.keys())),));
2059 oParser.add_option('--test-size', dest = 'sTestSize', default = InstructionTestGen.ksTestSize_Medium,
2060 choices = InstructionTestGen.kasTestSizes,
2061 help = 'Selects the test size.');
2062
2063 (oOptions, asArgs) = oParser.parse_args();
2064 if len(asArgs) > 0:
2065 oParser.print_help();
2066 return RTEXITCODE_SYNTAX
2067 if oOptions.sOutputBase is None:
2068 print('syntax error: Missing required option --output-base.', file = sys.stderr);
2069 return RTEXITCODE_SYNTAX
2070
2071 #
2072 # Instantiate the program class and run it.
2073 #
2074 oProgram = InstructionTestGen(oOptions);
2075 return oProgram.run();
2076
2077
2078if __name__ == '__main__':
2079 sys.exit(InstructionTestGen.main());
2080
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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