VirtualBox

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

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

-> weinstadt.

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

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