VirtualBox

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

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

SIB hacking in progress.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 53.4 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: InstructionTestGen.py 46771 2013-06-25 08:26:31Z 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: 46771 $";
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 Register names.
93## @{
94g_asGRegs64NoSp = ('rax', 'rcx', 'rdx', 'rbx', None, 'rbp', 'rsi', 'rdi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15');
95g_asGRegs64 = ('rax', 'rcx', 'rdx', 'rbx', 'rsp', 'rbp', 'rsi', 'rdi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15');
96g_asGRegs32NoSp = ('eax', 'ecx', 'edx', 'ebx', None, 'ebp', 'esi', 'edi',
97 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d');
98g_asGRegs32 = ('eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi',
99 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d');
100g_asGRegs16NoSp = ('ax', 'cx', 'dx', 'bx', None, 'bp', 'si', 'di',
101 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w');
102g_asGRegs16 = ('ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di',
103 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w');
104g_asGRegs8 = ('al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh');
105g_asGRegs8Rex = ('al', 'cl', 'dl', 'bl', 'spl', 'bpl', 'sil', 'dil',
106 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b');
107## @}
108
109
110## @name Random
111## @{
112g_oMyRand = random.SystemRandom()
113def randU16():
114 """ Unsigned 16-bit random number. """
115 return g_oMyRand.getrandbits(16);
116
117def randU32():
118 """ Unsigned 32-bit random number. """
119 return g_oMyRand.getrandbits(32);
120
121def randU64():
122 """ Unsigned 64-bit random number. """
123 return g_oMyRand.getrandbits(64);
124
125def randUxx(cBits):
126 """ Unsigned 8-, 16-, 32-, or 64-bit random number. """
127 return g_oMyRand.getrandbits(cBits);
128
129def randUxxList(cBits, cElements):
130 """ List of nsigned 8-, 16-, 32-, or 64-bit random numbers. """
131 return [randUxx(cBits) for _ in range(cElements)];
132## @}
133
134
135
136
137## @name Instruction Emitter Helpers
138## @{
139
140def calcRexPrefixForTwoModRmRegs(iReg, iRm, bOtherRexPrefixes = 0):
141 """
142 Calculates a rex prefix if neccessary given the two registers
143 and optional rex size prefixes.
144 Returns an empty array if not necessary.
145 """
146 bRex = bOtherRexPrefixes;
147 if iReg >= 8:
148 bRex |= X86_OP_REX_R;
149 if iRm >= 8:
150 bRex |= X86_OP_REX_B;
151 if bRex == 0:
152 return [];
153 return [bRex,];
154
155def calcModRmForTwoRegs(iReg, iRm):
156 """
157 Calculate the RM byte for two registers.
158 Returns an array with one byte in it.
159 """
160 bRm = (0x3 << X86_MODRM_MOD_SHIFT) \
161 | ((iReg << X86_MODRM_REG_SHIFT) & X86_MODRM_REG_MASK) \
162 | (iRm & X86_MODRM_RM_MASK);
163 return [bRm,];
164
165## @}
166
167
168## @name Misc
169## @{
170
171def convU32ToSigned(u32):
172 """ Converts a 32-bit unsigned value to 32-bit signed. """
173 if u32 < 0x80000000:
174 return u32;
175 return u32 - UINT32_MAX - 1;
176
177def gregName(iReg, cBits, fRexByteRegs = True):
178 """ Gets the name of a general register by index and width. """
179 if cBits == 64:
180 return g_asGRegs64[iReg];
181 if cBits == 32:
182 return g_asGRegs32[iReg];
183 if cBits == 16:
184 return g_asGRegs16[iReg];
185 assert cBits == 8;
186 if fRexByteRegs:
187 return g_asGRegs8Rex[iReg];
188 return g_asGRegs8[iReg];
189
190## @}
191
192
193class TargetEnv(object):
194 """
195 Target Runtime Environment.
196 """
197
198 ## @name CPU Modes
199 ## @{
200 ksCpuMode_Real = 'real';
201 ksCpuMode_Protect = 'prot';
202 ksCpuMode_Paged = 'paged';
203 ksCpuMode_Long = 'long';
204 ksCpuMode_V86 = 'v86';
205 ## @}
206
207 ## @name Instruction set.
208 ## @{
209 ksInstrSet_16 = '16';
210 ksInstrSet_32 = '32';
211 ksInstrSet_64 = '64';
212 ## @}
213
214 def __init__(self, sName,
215 sInstrSet = ksInstrSet_32,
216 sCpuMode = ksCpuMode_Paged,
217 iRing = 3,
218 ):
219 self.sName = sName;
220 self.sInstrSet = sInstrSet;
221 self.sCpuMode = sCpuMode;
222 self.iRing = iRing;
223 self.asGRegs = g_asGRegs64 if self.is64Bit() else g_asGRegs32;
224 self.asGRegsNoSp = g_asGRegs64NoSp if self.is64Bit() else g_asGRegs32NoSp;
225
226 def isUsingIprt(self):
227 """ Whether it's an IPRT environment or not. """
228 return self.sName.startswith('iprt');
229
230 def is64Bit(self):
231 """ Whether it's a 64-bit environment or not. """
232 return self.sInstrSet == self.ksInstrSet_64;
233
234 def getDefOpBits(self):
235 """ Get the default operand size as a bit count. """
236 if self.sInstrSet == self.ksInstrSet_16:
237 return 16;
238 return 32;
239
240 def getDefOpBytes(self):
241 """ Get the default operand size as a byte count. """
242 return self.getDefOpBits() / 8;
243
244 def getMaxOpBits(self):
245 """ Get the max operand size as a bit count. """
246 if self.sInstrSet == self.ksInstrSet_64:
247 return 64;
248 return 32;
249
250 def getMaxOpBytes(self):
251 """ Get the max operand size as a byte count. """
252 return self.getMaxOpBits() / 8;
253
254 def getDefAddrBits(self):
255 """ Get the default address size as a bit count. """
256 if self.sInstrSet == self.ksInstrSet_16:
257 return 16;
258 if self.sInstrSet == self.ksInstrSet_32:
259 return 32;
260 return 64;
261
262 def getDefAddrBytes(self):
263 """ Get the default address size as a byte count. """
264 return self.getDefAddrBits() / 8;
265
266 def getGRegCount(self):
267 """ Get the number of general registers. """
268 if self.sInstrSet == self.ksInstrSet_64:
269 return 16;
270 return 8;
271
272 def randGRegNoSp(self):
273 """ Returns a random general register number, excluding the SP register. """
274 iReg = randU16();
275 return iReg % (16 if self.is64Bit() else 8);
276
277 def getAddrModes(self):
278 """ Gets a list of addressing mode (16, 32, or/and 64). """
279 if self.sInstrSet == self.ksInstrSet_16:
280 return [16, 32];
281 if self.sInstrSet == self.ksInstrSet_32:
282 return [32, 16];
283 return [64, 32];
284
285
286## Target environments.
287g_dTargetEnvs = {
288 'iprt-r3-32': TargetEnv('iprt-r3-32', TargetEnv.ksInstrSet_32, TargetEnv.ksCpuMode_Protect, 3),
289 'iprt-r3-64': TargetEnv('iprt-r3-64', TargetEnv.ksInstrSet_64, TargetEnv.ksCpuMode_Long, 3),
290};
291
292
293class InstrTestBase(object):
294 """
295 Base class for testing one instruction.
296 """
297
298 def __init__(self, sName, sInstr = None):
299 self.sName = sName;
300 self.sInstr = sInstr if sInstr else sName.split()[0];
301
302 def isApplicable(self, oGen):
303 """
304 Tests if the instruction test is applicable to the selected environment.
305 """
306 _ = oGen;
307 return True;
308
309 def generateTest(self, oGen, sTestFnName):
310 """
311 Emits the test assembly code.
312 """
313 oGen.write(';; @todo not implemented. This is for the linter: %s, %s\n' % (oGen, sTestFnName));
314 return True;
315
316 def generateInputs(self, cbEffOp, cbMaxOp, oGen, fLong = False):
317 """ Generate a list of inputs. """
318 if fLong:
319 #
320 # Try do extremes as well as different ranges of random numbers.
321 #
322 auRet = [0, 1, ];
323 if cbMaxOp >= 1:
324 auRet += [ UINT8_MAX / 2, UINT8_MAX / 2 + 1, UINT8_MAX ];
325 if cbMaxOp >= 2:
326 auRet += [ UINT16_MAX / 2, UINT16_MAX / 2 + 1, UINT16_MAX ];
327 if cbMaxOp >= 4:
328 auRet += [ UINT32_MAX / 2, UINT32_MAX / 2 + 1, UINT32_MAX ];
329 if cbMaxOp >= 8:
330 auRet += [ UINT64_MAX / 2, UINT64_MAX / 2 + 1, UINT64_MAX ];
331
332 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
333 for cBits, cValues in ( (8, 4), (16, 4), (32, 8), (64, 8) ):
334 if cBits < cbMaxOp * 8:
335 auRet += randUxxList(cBits, cValues);
336 cWanted = 16;
337 elif oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
338 for cBits, cValues in ( (8, 8), (16, 8), (24, 2), (32, 16), (40, 1), (48, 1), (56, 1), (64, 16) ):
339 if cBits < cbMaxOp * 8:
340 auRet += randUxxList(cBits, cValues);
341 cWanted = 64;
342 else:
343 for cBits, cValues in ( (8, 16), (16, 16), (24, 4), (32, 64), (40, 4), (48, 4), (56, 4), (64, 64) ):
344 if cBits < cbMaxOp * 8:
345 auRet += randUxxList(cBits, cValues);
346 cWanted = 168;
347 if len(auRet) < cWanted:
348 auRet += randUxxList(cbEffOp * 8, cWanted - len(auRet));
349 else:
350 #
351 # Short list, just do some random numbers.
352 #
353 auRet = [];
354 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
355 auRet += randUxxList(cbMaxOp, 1);
356 elif oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
357 auRet += randUxxList(cbMaxOp, 2);
358 else:
359 auRet = [];
360 for cBits in (8, 16, 32, 64):
361 if cBits < cbMaxOp * 8:
362 auRet += randUxxList(cBits, 1);
363 return auRet;
364
365
366class InstrTest_MemOrGreg_2_Greg(InstrTestBase):
367 """
368 Instruction reading memory or general register and writing the result to a
369 general register.
370 """
371
372 def __init__(self, sName, fnCalcResult, sInstr = None, acbOpVars = None):
373 InstrTestBase.__init__(self, sName, sInstr);
374 self.fnCalcResult = fnCalcResult;
375 self.acbOpVars = [ 1, 2, 4, 8 ] if not acbOpVars else list(acbOpVars);
376
377 ## @name Test Instruction Writers
378 ## @{
379
380 def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
381 """ Writes the instruction with two general registers as operands. """
382 if cbEffOp == 8:
383 oGen.write(' %s %s, %s\n' % (self.sInstr, g_asGRegs64[iOp1], g_asGRegs64[iOp2]));
384 elif cbEffOp == 4:
385 oGen.write(' %s %s, %s\n' % (self.sInstr, g_asGRegs32[iOp1], g_asGRegs32[iOp2]));
386 elif cbEffOp == 2:
387 oGen.write(' %s %s, %s\n' % (self.sInstr, g_asGRegs16[iOp1], g_asGRegs16[iOp2]));
388 elif cbEffOp == 1:
389 oGen.write(' %s %s, %s\n' % (self.sInstr, g_asGRegs8Rex[iOp1], g_asGRegs8Rex[iOp2]));
390 else:
391 assert False;
392 return True;
393
394
395 def writeInstrGregPureRM(self, cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen):
396 """ Writes the instruction with two general registers as operands. """
397 if iOp2 == 13 and iMod == 0 and cAddrBits == 64: # Alt rip encoding, yasm isn't helping, do what we can.
398 if cbEffOp == 2:
399 oGen.write(' db %#04x\n' % (X86_OP_PRF_SIZE_OP,));
400 bRex = X86_OP_REX_B;
401 if iOp1 >= 8:
402 bRex |= X86_OP_REX_R;
403 if cbEffOp == 8:
404 bRex |= X86_OP_REX_W;
405 oGen.write(' db %#04x\n' % (bRex,));
406 if cbEffOp == 1:
407 oGen.write(' %s %s, [' % (self.sInstr, g_asGRegs8[iOp1 & 0x7],));
408 else:
409 oGen.write(' %s %s, [' % (self.sInstr, g_asGRegs32[iOp1 & 0x7],));
410 elif cbEffOp == 8:
411 oGen.write(' %s %s, [' % (self.sInstr, g_asGRegs64[iOp1],));
412 elif cbEffOp == 4:
413 oGen.write(' %s %s, [' % (self.sInstr, g_asGRegs32[iOp1],));
414 elif cbEffOp == 2:
415 oGen.write(' %s %s, [' % (self.sInstr, g_asGRegs16[iOp1],));
416 elif cbEffOp == 1:
417 oGen.write(' %s %s, [' % (self.sInstr, g_asGRegs8Rex[iOp1],));
418 else:
419 assert False;
420
421 if (iOp2 == 5 or iOp2 == 13) and iMod == 0:
422 oGen.write('VBINSTST_NAME(g_u%sData)' % (cbEffOp * 8,))
423 if oGen.oTarget.is64Bit():
424 oGen.write(' wrt rip');
425 else:
426 if iMod == 1:
427 oGen.write('byte %d + ' % (offDisp,));
428 elif iMod == 2:
429 oGen.write('dword %d + ' % (offDisp,));
430 else:
431 assert iMod == 0;
432
433 if cAddrBits == 64:
434 oGen.write(g_asGRegs64[iOp2]);
435 elif cAddrBits == 32:
436 oGen.write(g_asGRegs32[iOp2]);
437 elif cAddrBits == 16:
438 assert False; ## @todo implement 16-bit addressing.
439 else:
440 assert False, str(cAddrBits);
441
442 oGen.write(']\n');
443 return True;
444
445 def writeInstrGregSibLabel(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, oGen):
446 """ Writes the instruction taking a register and a lable, SIB form. """
447 ## @todo Dunno how to convince yasm to generate these. Considering patching it.
448 oGen.write(' %s %s, [VBINSTST_NAME(g_u%sData) xWrtRIP]\n'
449 % (self.sInstr, gregName(iOp1, cbEffOp * 8),));
450 return True;
451
452 def writeInstrGregSibScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
453 ## @todo Dunno how to convince yasm to generate SIB variants for iScale == 1 here. Considering patching it.
454 oGen.write(' %s %s, [%s * %#x'
455 % (self.sInstr, gregName(iOp1, cbEffOp * 8), gregName(iIndexReg, cAddrBits), iScale,));
456 if offDisp is not None:
457 oGen.write(' + %#x' % (offDisp,));
458 oGen.write('] ; iScale=%s\n' % (iScale,));
459 _ = iBaseReg;
460 return True;
461
462 def writeInstrGregSibBase(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
463 ## @todo Dunno how to convince yasm to generate SIB variants for iScale == 1 here. Considering patching it.
464 oGen.write(' %s %s, [%s'
465 % (self.sInstr, gregName(iOp1, cbEffOp * 8), gregName(iBaseReg, cAddrBits), iScale,));
466 if offDisp is not None:
467 oGen.write(' + %#x' % (offDisp,));
468 oGen.write('] ; iScale=%s\n' % (iScale,));
469 _ = iIndexReg;
470 return True;
471
472 def writeInstrGregSibBaseAndScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
473 return True;
474
475 ## @}
476
477
478 ## @name Memory setups
479 ## @{
480 def generateMemSetupReadByLabel(self, oGen, cAddrBits, uInput):
481 """ Sets up memory for a memory read. """
482 oGen.pushConst(uInput);
483 oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
484 return True;
485
486 def generateMemSetupReadByReg(self, oGen, cAddrBits, cbEffOp, iReg1, uInput, offDisp = None):
487 """ Sets up memory for a memory read indirectly addressed thru one register and optional displacement. """
488 oGen.pushConst(uInput);
489 oGen.write(' call VBINSTST_NAME(%s)\n'
490 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iReg1, offDisp),));
491 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iReg1],));
492 return True;
493
494 def generateMemSetupReadByScaledReg(self, oGen, cAddrBits, cbEffOp, iReg2, iScale, uInput, offDisp = None):
495 """ Sets up memory for a memory read indirectly addressed thru one register and optional displacement. """
496 oGen.pushConst(uInput);
497 oGen.write(' call VBINSTST_NAME(%s)\n'
498 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iReg2, offDisp, iScale = iScale),));
499 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iReg1],));
500 return True;
501
502 def generateMemSetupReadByBaseAndScaledReg(self, oGen, cAddrBits, cbEffOp, iBaseReg, iIndexReg, iScale, uInput, offDisp):
503 """ Sets up memory for a memory read indirectly addressed thru two registers with optional displacement. """
504 oGen.pushConst(uInput);
505 if iScale == 1:
506 oGen.write(' call VBINSTST_NAME(%s)\n'
507 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iReg1, offDisp),));
508 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iReg1],));
509 return True;
510
511 def generateMemSetupPureRM(self, oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp = None):
512 """ Sets up memory for a pure R/M addressed read, iOp2 being the R/M value. """
513 oGen.pushConst(uInput);
514 assert offDisp is None or iMod != 0;
515 if (iOp2 != 5 and iOp2 != 13) or iMod != 0:
516 oGen.write(' call VBINSTST_NAME(%s)\n'
517 % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iOp2, offDisp),));
518 else:
519 oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
520 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
521 return True;
522
523 ## @}
524
525 def generateOneStdTestGregGreg(self, oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput, uResult):
526 """ Generate one standard test. """
527 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
528 oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2], uInput,));
529 oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
530 self.writeInstrGregGreg(cbEffOp, iOp1, iOp2, oGen);
531 oGen.pushConst(uResult);
532 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
533 _ = cbMaxOp;
534 return True;
535
536 def generateOneStdTestGregMemNoSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iOp2, uInput, uResult):
537 """ Generate mode 0, 1 and 2 test for the R/M=iOp2. """
538 if cAddrBits == 16:
539 _ = cbMaxOp;
540 else:
541 iMod = 0; # No disp, except for i=5.
542 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
543 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput);
544 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, None, oGen);
545 oGen.pushConst(uResult);
546 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
547
548 if iOp2 != 5 and iOp2 != 13:
549 iMod = 1;
550 for offDisp in oGen.getDispForMod(iMod):
551 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
552 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp);
553 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen);
554 oGen.pushConst(uResult);
555 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
556
557 iMod = 2;
558 for offDisp in oGen.getDispForMod(iMod):
559 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
560 self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp);
561 self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen);
562 oGen.pushConst(uResult);
563 oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
564
565 return True;
566
567 def generateOneStdTestGregMemNoSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod,
568 iBaseReg, iIndexReg, iScale, uInput, uResult):
569 """ Generate one SIB variations. """
570 for offDisp in oGen.getDispForMod(iMod, cbEffOp):
571 if ((iBaseReg == 5 or iBaseReg == 13) and iMod == 0):
572 if iIndexReg == 4:
573 if cAddrBits == 64:
574 continue; # skipping.
575 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
576 self.generateMemSetupReadByLabel(oGen, cAddrBits, uInput);
577 self.writeInstrGregSibLabel(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, oGen);
578 sChecker = oGen.needGRegChecker(iOp1);
579 else:
580 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
581 self.generateMemSetupReadByScaledReg(oGen, cAddrBits, cbEffOp, iIndexReg, iScale, uInput, offDisp);
582 self.writeInstrGregSibScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
583 sChecker = oGen.needGRegChecker(iOp1, iIndexReg);
584 else:
585 oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
586 if iIndexReg == 4:
587 self.generateMemSetupReadByReg(oGen, cAddrBits, cbEffOp, iBaseReg, uInput, offDisp);
588 self.writeInstrGregSibBase(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
589 sChecker = oGen.needGRegChecker(iOp1, iBaseReg);
590 else:
591 self.generateMemSetupReadByBaseAndScaledReg(oGen, cAddrBits, cbEffOp, iBaseReg,
592 iIndexReg, iScale, uInput, offDisp);
593 self.writeInstrGregSibBaseAndScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
594 sChecker = oGen.needGRegChecker(iOp1, iBaseReg, iIndexReg);
595 oGen.pushConst(uResult);
596 oGen.write(' call VBINSTST_NAME(%s)\n' % (sChecker,));
597 return True;
598
599 def generateStdTestGregMemSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, auInputs):
600 """ Generate all SIB variations for the given iOp1 (reg) value. """
601 assert cAddrBits in [32, 64];
602 for iBaseReg in range(len(oGen.oTarget.asGRegs)):
603 for iIndexReg in range(len(oGen.oTarget.asGRegs)):
604 if iBaseReg == 4 or iIndexReg == 4: # no RSP testing atm.
605 continue;
606 for iMod in [0, 1, 2]:
607 if iBaseReg == iOp1 and ((iBaseReg != 5 and iBaseReg != 13) or iMod != 0) and cAddrBits != cbMaxOp:
608 continue; # Don't know the high bit of the address ending up the result - skip it for now.
609 for iScale in (1, 2, 4, 8):
610 for uInput in auInputs:
611 oGen.newSubTest();
612 uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[iOp1], oGen);
613 self.generateOneStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod,
614 iBaseReg, iIndexReg, iScale, uInput, uResult);
615
616 return True;
617
618
619 def generateStandardTests(self, oGen):
620 """ Generate standard tests. """
621
622 # Parameters.
623 cbDefOp = oGen.oTarget.getDefOpBytes();
624 cbMaxOp = oGen.oTarget.getMaxOpBytes();
625 auShortInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen);
626 auLongInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen, fLong = True);
627 iLongOp1 = oGen.oTarget.randGRegNoSp();
628 iLongOp2 = oGen.oTarget.randGRegNoSp();
629 oOp2Range = range(oGen.oTarget.getGRegCount());
630 oOp1MemRange = range(oGen.oTarget.getGRegCount());
631 if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
632 oOp2Range = [iLongOp2,];
633 oOp1MemRange = [iLongOp1,];
634
635 # Register tests
636 if True:
637 for cbEffOp in self.acbOpVars:
638 if cbEffOp > cbMaxOp:
639 continue;
640 for iOp1 in range(oGen.oTarget.getGRegCount()):
641 if oGen.oTarget.asGRegsNoSp[iOp1] is None:
642 continue;
643 for iOp2 in oOp2Range:
644 if oGen.oTarget.asGRegsNoSp[iOp2] is None:
645 continue;
646 for uInput in (auLongInputs if iOp1 == iLongOp1 and iOp2 == iLongOp2 else auShortInputs):
647 uResult = self.fnCalcResult(cbEffOp, uInput,
648 oGen.auRegValues[iOp1] if iOp1 != iOp2 else uInput, oGen);
649 oGen.newSubTest();
650 self.generateOneStdTestGregGreg(oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput, uResult);
651
652 # Memory test.
653 if True:
654 for cbEffOp in self.acbOpVars:
655 if cbEffOp > cbMaxOp:
656 continue;
657 for iOp1 in oOp1MemRange:
658 if oGen.oTarget.asGRegsNoSp[iOp1] is None:
659 continue;
660 for cAddrBits in oGen.oTarget.getAddrModes():
661 for iOp2 in range(len(oGen.oTarget.asGRegs)):
662 if iOp2 != 4 or cAddrBits == 16:
663 for uInput in (auLongInputs if iOp1 == iLongOp1 and False else auShortInputs):
664 oGen.newSubTest();
665 if iOp1 == iOp2 and iOp2 != 5 and iOp2 != 13 and cbEffOp != cbMaxOp:
666 continue; # Don't know the high bit of the address ending up the result - skip it for now.
667 uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[iOp1], oGen);
668 self.generateOneStdTestGregMemNoSib(oGen, cAddrBits, cbEffOp, cbMaxOp,
669 iOp1, iOp2, uInput, uResult);
670 else:
671 # SIB.
672 self.generateStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, auInputs);
673
674 return True;
675
676 def generateTest(self, oGen, sTestFnName):
677 oGen.write('VBINSTST_BEGINPROC %s\n' % (sTestFnName,));
678 #oGen.write(' int3\n');
679
680 self.generateStandardTests(oGen);
681
682 #oGen.write(' int3\n');
683 oGen.write(' ret\n');
684 oGen.write('VBINSTST_ENDPROC %s\n' % (sTestFnName,));
685 return True;
686
687
688
689class InstrTest_Mov_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
690 """
691 Tests MOV Gv,Ev.
692 """
693 def __init__(self):
694 InstrTest_MemOrGreg_2_Greg.__init__(self, 'mov Gv,Ev', self.calc_mov);
695
696 @staticmethod
697 def calc_mov(cbEffOp, uInput, uCur, oGen):
698 """ Calculates the result of a mov instruction."""
699 if cbEffOp == 8:
700 return uInput & UINT64_MAX;
701 if cbEffOp == 4:
702 return uInput & UINT32_MAX;
703 if cbEffOp == 2:
704 return (uCur & 0xffffffffffff0000) | (uInput & UINT16_MAX);
705 assert cbEffOp == 1; _ = oGen;
706 return (uCur & 0xffffffffffffff00) | (uInput & UINT8_MAX);
707
708
709class InstrTest_MovSxD_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
710 """
711 Tests MOVSXD Gv,Ev.
712 """
713 def __init__(self):
714 InstrTest_MemOrGreg_2_Greg.__init__(self, 'movsxd Gv,Ev', self.calc_movsxd, acbOpVars = [ 8, 4, 2, ]);
715
716 def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
717 if cbEffOp == 8:
718 oGen.write(' %s %s, %s\n' % (self.sInstr, g_asGRegs64[iOp1], g_asGRegs32[iOp2]));
719 elif cbEffOp == 4 or cbEffOp == 2:
720 abInstr = [];
721 if cbEffOp != oGen.oTarget.getDefOpBytes():
722 abInstr.append(X86_OP_PRF_SIZE_OP);
723 abInstr += calcRexPrefixForTwoModRmRegs(iOp1, iOp2);
724 abInstr.append(0x63);
725 abInstr += calcModRmForTwoRegs(iOp1, iOp2);
726 oGen.writeInstrBytes(abInstr);
727 else:
728 assert False;
729 assert False;
730 return True;
731
732 def isApplicable(self, oGen):
733 return oGen.oTarget.is64Bit();
734
735 @staticmethod
736 def calc_movsxd(cbEffOp, uInput, uCur, oGen):
737 """
738 Calculates the result of a movxsd instruction.
739 Returns the result value (cbMaxOp sized).
740 """
741 _ = oGen;
742 if cbEffOp == 8 and (uInput & RT_BIT_32(31)):
743 return (UINT32_MAX << 32) | (uInput & UINT32_MAX);
744 if cbEffOp == 2:
745 return (uCur & 0xffffffffffff0000) | (uInput & 0xffff);
746 return uInput & UINT32_MAX;
747
748
749## Instruction Tests.
750g_aoInstructionTests = [
751 InstrTest_Mov_Gv_Ev(),
752 #InstrTest_MovSxD_Gv_Ev(),
753];
754
755
756class InstructionTestGen(object):
757 """
758 Instruction Test Generator.
759 """
760
761 ## @name Test size
762 ## @{
763 ksTestSize_Large = 'large';
764 ksTestSize_Medium = 'medium';
765 ksTestSize_Tiny = 'tiny';
766 ## @}
767 kasTestSizes = ( ksTestSize_Large, ksTestSize_Medium, ksTestSize_Tiny );
768
769
770
771 def __init__(self, oOptions):
772 self.oOptions = oOptions;
773 self.oTarget = g_dTargetEnvs[oOptions.sTargetEnv];
774
775 # Calculate the number of output files.
776 self.cFiles = 1;
777 if len(g_aoInstructionTests) > self.oOptions.cInstrPerFile:
778 self.cFiles = len(g_aoInstructionTests) / self.oOptions.cInstrPerFile;
779 if self.cFiles * self.oOptions.cInstrPerFile < len(g_aoInstructionTests):
780 self.cFiles += 1;
781
782 # Fix the known register values.
783 self.au64Regs = randUxxList(64, 16);
784 self.au32Regs = [(self.au64Regs[i] & UINT32_MAX) for i in range(8)];
785 self.au16Regs = [(self.au64Regs[i] & UINT16_MAX) for i in range(8)];
786 self.auRegValues = self.au64Regs if self.oTarget.is64Bit() else self.au32Regs;
787
788 # Declare state variables used while generating.
789 self.oFile = sys.stderr;
790 self.iFile = -1;
791 self.sFile = '';
792 self.dCheckFns = dict();
793 self.dMemSetupFns = dict();
794 self.d64BitConsts = dict();
795
796
797 #
798 # Methods used by instruction tests.
799 #
800
801 def write(self, sText):
802 """ Writes to the current output file. """
803 return self.oFile.write(unicode(sText));
804
805 def writeln(self, sText):
806 """ Writes a line to the current output file. """
807 self.write(sText);
808 return self.write('\n');
809
810 def writeInstrBytes(self, abInstr):
811 """
812 Emits an instruction given as a sequence of bytes values.
813 """
814 self.write(' db %#04x' % (abInstr[0],));
815 for i in range(1, len(abInstr)):
816 self.write(', %#04x' % (abInstr[i],));
817 return self.write('\n');
818
819 def newSubTest(self):
820 """
821 Indicates that a new subtest has started.
822 """
823 self.write(' mov dword [VBINSTST_NAME(g_uVBInsTstSubTestIndicator) xWrtRIP], __LINE__\n');
824 return True;
825
826 def needGRegChecker(self, iReg1, iReg2 = None, iReg3 = None):
827 """
828 Records the need for a given register checker function, returning its label.
829 """
830 assert iReg1 < 32; assert iReg2 < 32;
831 iRegs = iReg1 + iReg2 * 32;
832 if iRegs in self.dCheckFns:
833 self.dCheckFns[iRegs] += 1;
834 else:
835 self.dCheckFns[iRegs] = 1;
836 return 'Common_Check_%s_%s' % (self.oTarget.asGRegs[iReg1], self.oTarget.asGRegs[iReg2]);
837
838 def needGRegMemSetup(self, cAddrBits, cbEffOp, iBaseReg, offDisp = None, iIndexReg = None, iScale = 1):
839 """
840 Records the need for a given register checker function, returning its label.
841 """
842 sName = '%ubit_U%u' % (cAddrBits, cbEffOp * 8,);
843 if iBaseReg is not None:
844 sName += '_%s' % (gregName(iBaseReg, cAddrBits),);
845 sName += '_x%u' % (iScale,);
846 if iIndexReg is not None:
847 sName += '_%s' % (gregName(iIndexReg, cAddrBits),);
848 if offDisp is not None:
849 sName += '_%#010x' % (offDisp & UINT32_MAX, );
850 if sName in self.dCheckFns:
851 self.dMemSetupFns[sName] += 1;
852 else:
853 self.dMemSetupFns[sName] = 1;
854 return 'Common_MemSetup_' + sName;
855
856 def need64BitConstant(self, uVal):
857 """
858 Records the need for a 64-bit constant, returning its label.
859 These constants are pooled to attempt reduce the size of the whole thing.
860 """
861 assert uVal >= 0 and uVal <= UINT64_MAX;
862 if uVal in self.d64BitConsts:
863 self.d64BitConsts[uVal] += 1;
864 else:
865 self.d64BitConsts[uVal] = 1;
866 return 'g_u64Const_0x%016x' % (uVal, );
867
868 def pushConst(self, uResult):
869 """
870 Emits a push constant value, taking care of high values on 64-bit hosts.
871 """
872 if self.oTarget.is64Bit() and uResult >= 0x80000000:
873 self.write(' push qword [%s wrt rip]\n' % (self.need64BitConstant(uResult),));
874 else:
875 self.write(' push dword 0x%x\n' % (uResult,));
876 return True;
877
878 def getDispForMod(self, iMod, cbAlignment = 1):
879 """
880 Get a set of address dispositions for a given addressing mode.
881 The alignment restriction is for SIB scaling.
882 """
883 assert cbAlignment in [1, 2, 4, 8];
884 if iMod == 0:
885 aoffDisp = [ None, ];
886 elif iMod == 1:
887 aoffDisp = [ 127 & ~cbAlignment, -128 ];
888 elif iMod == 2:
889 aoffDisp = [ 2147483647 & ~(cbAlignment - 1), -2147483648 ];
890 else: assert False;
891 return aoffDisp;
892
893
894 #
895 # Internal machinery.
896 #
897
898 def _calcTestFunctionName(self, oInstrTest, iInstrTest):
899 """
900 Calc a test function name for the given instruction test.
901 """
902 sName = 'TestInstr%03u_%s' % (iInstrTest, oInstrTest.sName);
903 return sName.replace(',', '_').replace(' ', '_').replace('%', '_');
904
905 def _generateFileHeader(self, ):
906 """
907 Writes the file header.
908 Raises exception on trouble.
909 """
910 self.write('; $Id: InstructionTestGen.py 46771 2013-06-25 08:26:31Z vboxsync $\n'
911 ';; @file %s\n'
912 '; Autogenerate by %s %s. DO NOT EDIT\n'
913 ';\n'
914 '\n'
915 ';\n'
916 '; Headers\n'
917 ';\n'
918 '%%include "env-%s.mac"\n'
919 % ( os.path.basename(self.sFile),
920 os.path.basename(__file__), __version__[11:-1],
921 self.oTarget.sName,
922 ) );
923 # Target environment specific init stuff.
924
925 #
926 # Global variables.
927 #
928 self.write('\n\n'
929 ';\n'
930 '; Globals\n'
931 ';\n');
932 self.write('VBINSTST_BEGINDATA\n'
933 'VBINSTST_GLOBALNAME_EX g_pvLow16Mem4K, data hidden\n'
934 ' dq 0\n'
935 'VBINSTST_GLOBALNAME_EX g_pvLow32Mem4K, data hidden\n'
936 ' dq 0\n'
937 'VBINSTST_GLOBALNAME_EX g_pvMem4K, data hidden\n'
938 ' dq 0\n'
939 'VBINSTST_GLOBALNAME_EX g_uVBInsTstSubTestIndicator, data hidden\n'
940 ' dd 0\n'
941 'VBINSTST_BEGINCODE\n'
942 );
943 self.write('%ifdef RT_ARCH_AMD64\n');
944 for i in range(len(g_asGRegs64)):
945 self.write('g_u64KnownValue_%s: dq 0x%x\n' % (g_asGRegs64[i], self.au64Regs[i]));
946 self.write('%endif\n\n')
947
948 #
949 # Common functions.
950 #
951
952 # Loading common values.
953 self.write('\n\n'
954 'VBINSTST_BEGINPROC Common_LoadKnownValues\n'
955 '%ifdef RT_ARCH_AMD64\n');
956 for i in range(len(g_asGRegs64NoSp)):
957 if g_asGRegs64NoSp[i]:
958 self.write(' mov %s, 0x%x\n' % (g_asGRegs64NoSp[i], self.au64Regs[i],));
959 self.write('%else\n');
960 for i in range(8):
961 if g_asGRegs32NoSp[i]:
962 self.write(' mov %s, 0x%x\n' % (g_asGRegs32NoSp[i], self.au32Regs[i],));
963 self.write('%endif\n'
964 ' ret\n'
965 'VBINSTST_ENDPROC Common_LoadKnownValues\n'
966 '\n');
967
968 self.write('VBINSTST_BEGINPROC Common_CheckKnownValues\n'
969 '%ifdef RT_ARCH_AMD64\n');
970 for i in range(len(g_asGRegs64NoSp)):
971 if g_asGRegs64NoSp[i]:
972 self.write(' cmp %s, [g_u64KnownValue_%s wrt rip]\n'
973 ' je .ok_%u\n'
974 ' push %u ; register number\n'
975 ' push %s ; actual\n'
976 ' push qword [g_u64KnownValue_%s wrt rip] ; expected\n'
977 ' call VBINSTST_NAME(Common_BadValue)\n'
978 '.ok_%u:\n'
979 % ( g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i, i, g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i,));
980 self.write('%else\n');
981 for i in range(8):
982 if g_asGRegs32NoSp[i]:
983 self.write(' cmp %s, 0x%x\n'
984 ' je .ok_%u\n'
985 ' push %u ; register number\n'
986 ' push %s ; actual\n'
987 ' push dword 0x%x ; expected\n'
988 ' call VBINSTST_NAME(Common_BadValue)\n'
989 '.ok_%u:\n'
990 % ( g_asGRegs32NoSp[i], self.au32Regs[i], i, i, g_asGRegs32NoSp[i], self.au32Regs[i], i,));
991 self.write('%endif\n'
992 ' ret\n'
993 'VBINSTST_ENDPROC Common_CheckKnownValues\n'
994 '\n');
995
996 return True;
997
998 def _generateMemSetupFunctions(self):
999 """
1000 Generates the memory setup functions.
1001 """
1002 cDefAddrBits = self.oTarget.getDefAddrBits();
1003 for sName in self.dMemSetupFns:
1004 # Unpack it.
1005 asParams = sName.split('_');
1006 cAddrBits = int(asParams[0][:-3]);
1007 cEffOpBits = int(asParams[1][1:]);
1008 if cAddrBits == 64: asAddrGRegs = g_asGRegs64;
1009 elif cAddrBits == 32: asAddrGRegs = g_asGRegs32;
1010 else: asAddrGRegs = g_asGRegs16;
1011
1012 i = 2;
1013 if i < len(asParams[i]) and asParams[i]:
1014 sBaseReg = asParams[i];
1015 i += 1
1016 try:
1017 iBaseReg = asAddrGRegs.index(sBaseReg);
1018 except ValueError:
1019 assert False, 'sBaseReg=%s' % (sBaseReg,);
1020 raise;
1021
1022 u32Disp = None;
1023 if i < len(asParams) and len(asParams[i]) == 10:
1024 u32Disp = long(asParams[i], 16);
1025 i += 1;
1026
1027 sIndexReg = None;
1028 iIndexReg = None;
1029 if i < len(asParams):
1030 sIndexReg = asParams[i];
1031 iBaseReg = asAddrGRegs.index(sBaseReg);
1032 i += 1;
1033
1034 iScale = 1;
1035 if i < len(asParams):
1036 iScale = int(asParams[i]); assert iScale in [2, 4, 8];
1037 i += 1;
1038
1039 assert i == len(asParams), 'i=%d len=%d len[i]=%d (%s)' % (i, len(asParams), len(asParams[i]), asParams[i],);
1040
1041 # Prologue.
1042 iTmpReg1 = 0 if iBaseReg != 0 else 1;
1043 self.write('\n\n'
1044 'VBINSTST_BEGINPROC Common_MemSetup_%s\n'
1045 ' MY_PUSH_FLAGS\n'
1046 ' push %s\n'
1047 % (sName, self.oTarget.asGRegs[iTmpReg1], ));
1048 self.write('; cAddrBits=%s cEffOpBits=%s iBaseReg=%s u32Disp=%s iIndexReg=%s iScale=%s\n'
1049 % (cAddrBits, cEffOpBits, iBaseReg, u32Disp, iIndexReg, iScale,));
1050
1051 # Figure out what to use.
1052 if cEffOpBits == 64:
1053 sTmpReg1 = g_asGRegs64[iTmpReg1];
1054 sDataVar = 'VBINSTST_NAME(g_u64Data)';
1055 elif cEffOpBits == 32:
1056 sTmpReg1 = g_asGRegs32[iTmpReg1];
1057 sDataVar = 'VBINSTST_NAME(g_u32Data)';
1058 elif cEffOpBits == 16:
1059 sTmpReg1 = g_asGRegs16[iTmpReg1];
1060 sDataVar = 'VBINSTST_NAME(g_u16Data)';
1061 else:
1062 assert cEffOpBits == 8;
1063 sTmpReg1 = g_asGRegs8Rex[iTmpReg1];
1064 sDataVar = 'VBINSTST_NAME(g_u8Data)';
1065
1066 # Load the value and mem address, sorting the value there.
1067 self.write(' mov %s, [xSP + sCB + MY_PUSH_FLAGS_SIZE + xCB]\n' % (sTmpReg1,));
1068 if cAddrBits >= cDefAddrBits:
1069 self.write(' mov [%s xWrtRIP], %s\n' % (sDataVar, sTmpReg1,));
1070 self.write(' lea %s, [%s xWrtRIP]\n' % (sBaseReg, sDataVar,));
1071 else:
1072
1073 if cAddrBits == 16:
1074 self.write(' mov %s, [VBINSTST_NAME(g_pvLow16Mem4K) xWrtRIP]\n' % (sBaseReg,));
1075 else:
1076 self.write(' mov %s, [VBINSTST_NAME(g_pvLow32Mem4K) xWrtRIP]\n' % (sBaseReg,));
1077 self.write(' add %s, %s\n' % (sBaseReg, (randU16() << cEffOpBits) & 0xfff, ));
1078 self.write(' mov [%s], %s\n' % (sBaseReg, sTmpReg1, ));
1079
1080 # Adjust for disposition and scaling.
1081 if u32Disp is not None:
1082 self.write(' sub %s, %d\n' % ( sBaseReg, convU32ToSigned(u32Disp), ));
1083 if iIndexReg is not None:
1084 uIdxRegVal = randUxx(cAddrBits);
1085 self.write(' mov %s, %u\n' % ( sIndexReg, uIdxRegVal,));
1086 if cAddrBits == 64:
1087 self.write(' sub %s, %#06x\n' % ( sBaseReg, uIdxRegVal * iScale, ));
1088 elif cAddrBits == 16:
1089 self.write(' sub %s, %#06x\n' % ( sBaseReg, (uIdxRegVal * iScale) & UINT32_MAX, ));
1090 else:
1091 assert cAddrBits == 16;
1092 self.write(' sub %s, %#06x\n' % ( sBaseReg, (uIdxRegVal * iScale) & UINT16_MAX, ));
1093
1094 # Set upper bits that's supposed to be unused.
1095 if cDefAddrBits > cAddrBits or cAddrBits == 16:
1096 if cDefAddrBits == 64:
1097 assert cAddrBits == 32;
1098 self.write(' mov %s, %#018x\n'
1099 ' or %s, %s\n'
1100 % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
1101 g_asGRegs64[iBaseReg], g_asGRegs64[iTmpReg1],));
1102 if iIndexReg is not None:
1103 self.write(' mov %s, %#018x\n'
1104 ' or %s, %s\n'
1105 % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
1106 g_asGRegs64[iIndexReg], g_asGRegs64[iTmpReg1],));
1107 else:
1108 assert cDefAddrBits == 32; assert cAddrBits == 16;
1109 self.write(' or %s, %#010x\n'
1110 % ( g_asGRegs32[iBaseReg], randU32() & 0xffff0000, ));
1111 if iIndexReg is not None:
1112 self.write(' or %s, %#010x\n'
1113 % ( g_asGRegs32[iIndexReg], randU32() & 0xffff0000, ));
1114
1115 # Epilogue.
1116 self.write(' pop %s\n'
1117 ' MY_POP_FLAGS\n'
1118 ' ret sCB\n'
1119 'VBINSTST_ENDPROC Common_MemSetup_%s\n'
1120 % ( self.oTarget.asGRegs[iTmpReg1], sName,));
1121
1122
1123 def _generateFileFooter(self):
1124 """
1125 Generates file footer.
1126 """
1127
1128 # Register checking functions.
1129 for iRegs in self.dCheckFns:
1130 iReg1 = iRegs & 0x1f;
1131 sReg1 = self.oTarget.asGRegs[iReg1];
1132 iReg2 = (iRegs >> 5) & 0x1f;
1133 sReg2 = self.oTarget.asGRegs[iReg2];
1134 sPushSize = 'dword';
1135
1136 self.write('\n\n'
1137 '; Checks two register values, expected values pushed on the stack.\n'
1138 '; To save space, the callee cleans up the stack.'
1139 '; Ref count: %u\n'
1140 'VBINSTST_BEGINPROC Common_Check_%s_%s\n'
1141 ' MY_PUSH_FLAGS\n'
1142 % ( self.dCheckFns[iRegs], sReg1, sReg2, ) );
1143
1144 self.write(' cmp %s, [xSP + MY_PUSH_FLAGS_SIZE + xCB]\n'
1145 ' je .equal1\n'
1146 ' push %s %u ; register number\n'
1147 ' push %s ; actual\n'
1148 ' mov %s, [xSP + sCB*2 + MY_PUSH_FLAGS_SIZE + xCB]\n'
1149 ' push %s ; expected\n'
1150 ' call VBINSTST_NAME(Common_BadValue)\n'
1151 ' pop %s\n'
1152 ' pop %s\n'
1153 ' pop %s\n'
1154 '.equal1:\n'
1155 % ( sReg1, sPushSize, iReg1, sReg1, sReg1, sReg1, sReg1, sReg1, sReg1, ) );
1156 if iReg1 != iReg2: # If input and result regs are the same, only check the result.
1157 self.write(' cmp %s, [xSP + sCB + MY_PUSH_FLAGS_SIZE + xCB]\n'
1158 ' je .equal2\n'
1159 ' push %s %u ; register number\n'
1160 ' push %s ; actual\n'
1161 ' mov %s, [xSP + sCB*3 + MY_PUSH_FLAGS_SIZE + xCB]\n'
1162 ' push %s ; expected\n'
1163 ' call VBINSTST_NAME(Common_BadValue)\n'
1164 ' pop %s\n'
1165 ' pop %s\n'
1166 ' pop %s\n'
1167 '.equal2:\n'
1168 % ( sReg2, sPushSize, iReg2, sReg2, sReg2, sReg2, sReg2, sReg2, sReg2, ) );
1169
1170 if self.oTarget.is64Bit():
1171 self.write(' mov %s, [g_u64KnownValue_%s wrt rip]\n' % (sReg1, sReg1,));
1172 if iReg1 != iReg2:
1173 self.write(' mov %s, [g_u64KnownValue_%s wrt rip]\n' % (sReg2, sReg2,));
1174 else:
1175 self.write(' mov %s, 0x%x\n' % (sReg1, self.au32Regs[iReg1],));
1176 if iReg1 != iReg2:
1177 self.write(' mov %s, 0x%x\n' % (sReg2, self.au32Regs[iReg2],));
1178 self.write(' MY_POP_FLAGS\n'
1179 ' call VBINSTST_NAME(Common_CheckKnownValues)\n'
1180 ' ret sCB*2\n'
1181 'VBINSTST_ENDPROC Common_Check_%s_%s\n'
1182 % (sReg1, sReg2,));
1183
1184 # memory setup functions
1185 self._generateMemSetupFunctions();
1186
1187 # 64-bit constants.
1188 if len(self.d64BitConsts) > 0:
1189 self.write('\n\n'
1190 ';\n'
1191 '; 64-bit constants\n'
1192 ';\n');
1193 for uVal in self.d64BitConsts:
1194 self.write('g_u64Const_0x%016x: dq 0x%016x ; Ref count: %d\n' % (uVal, uVal, self.d64BitConsts[uVal], ) );
1195
1196 return True;
1197
1198 def _generateTests(self):
1199 """
1200 Generate the test cases.
1201 """
1202 for self.iFile in range(self.cFiles):
1203 if self.cFiles == 1:
1204 self.sFile = '%s.asm' % (self.oOptions.sOutputBase,)
1205 else:
1206 self.sFile = '%s-%u.asm' % (self.oOptions.sOutputBase, self.iFile)
1207 self.oFile = sys.stdout;
1208 if self.oOptions.sOutputBase != '-':
1209 self.oFile = io.open(self.sFile, 'w', encoding = 'utf-8');
1210
1211 self._generateFileHeader();
1212
1213 # Calc the range.
1214 iInstrTestStart = self.iFile * self.oOptions.cInstrPerFile;
1215 iInstrTestEnd = iInstrTestStart + self.oOptions.cInstrPerFile;
1216 if iInstrTestEnd > len(g_aoInstructionTests):
1217 iInstrTestEnd = len(g_aoInstructionTests);
1218
1219 # Generate the instruction tests.
1220 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1221 oInstrTest = g_aoInstructionTests[iInstrTest];
1222 self.write('\n'
1223 '\n'
1224 ';\n'
1225 '; %s\n'
1226 ';\n'
1227 % (oInstrTest.sName,));
1228 oInstrTest.generateTest(self, self._calcTestFunctionName(oInstrTest, iInstrTest));
1229
1230 # Generate the main function.
1231 self.write('\n\n'
1232 'VBINSTST_BEGINPROC TestInstrMain\n'
1233 ' MY_PUSH_ALL\n'
1234 ' sub xSP, 40h\n'
1235 '\n');
1236
1237 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1238 oInstrTest = g_aoInstructionTests[iInstrTest];
1239 if oInstrTest.isApplicable(self):
1240 self.write('%%ifdef ASM_CALL64_GCC\n'
1241 ' lea rdi, [.szInstr%03u wrt rip]\n'
1242 '%%elifdef ASM_CALL64_MSC\n'
1243 ' lea rcx, [.szInstr%03u wrt rip]\n'
1244 '%%else\n'
1245 ' mov xAX, .szInstr%03u\n'
1246 ' mov [xSP], xAX\n'
1247 '%%endif\n'
1248 ' VBINSTST_CALL_FN_SUB_TEST\n'
1249 ' call VBINSTST_NAME(%s)\n'
1250 % ( iInstrTest, iInstrTest, iInstrTest, self._calcTestFunctionName(oInstrTest, iInstrTest)));
1251
1252 self.write('\n'
1253 ' add xSP, 40h\n'
1254 ' MY_POP_ALL\n'
1255 ' ret\n\n');
1256 for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
1257 self.write('.szInstr%03u: db \'%s\', 0\n' % (iInstrTest, g_aoInstructionTests[iInstrTest].sName,));
1258 self.write('VBINSTST_ENDPROC TestInstrMain\n\n');
1259
1260 self._generateFileFooter();
1261 if self.oOptions.sOutputBase != '-':
1262 self.oFile.close();
1263 self.oFile = None;
1264 self.sFile = '';
1265
1266 return RTEXITCODE_SUCCESS;
1267
1268 def _runMakefileMode(self):
1269 """
1270 Generate a list of output files on standard output.
1271 """
1272 if self.cFiles == 1:
1273 print('%s.asm' % (self.oOptions.sOutputBase,));
1274 else:
1275 print(' '.join('%s-%s.asm' % (self.oOptions.sOutputBase, i) for i in range(self.cFiles)));
1276 return RTEXITCODE_SUCCESS;
1277
1278 def run(self):
1279 """
1280 Generates the tests or whatever is required.
1281 """
1282 if self.oOptions.fMakefileMode:
1283 return self._runMakefileMode();
1284 return self._generateTests();
1285
1286 @staticmethod
1287 def main():
1288 """
1289 Main function a la C/C++. Returns exit code.
1290 """
1291
1292 #
1293 # Parse the command line.
1294 #
1295 oParser = OptionParser(version = __version__[11:-1].strip());
1296 oParser.add_option('--makefile-mode', dest = 'fMakefileMode', action = 'store_true', default = False,
1297 help = 'Special mode for use to output a list of output files for the benefit of '
1298 'the make program (kmk).');
1299 oParser.add_option('--split', dest = 'cInstrPerFile', metavar = '<instr-per-file>', type = 'int', default = 9999999,
1300 help = 'Number of instruction to test per output file.');
1301 oParser.add_option('--output-base', dest = 'sOutputBase', metavar = '<file>', default = None,
1302 help = 'The output file base name, no suffix please. Required.');
1303 oParser.add_option('--target', dest = 'sTargetEnv', metavar = '<target>',
1304 default = 'iprt-r3-32',
1305 choices = g_dTargetEnvs.keys(),
1306 help = 'The target environment. Choices: %s'
1307 % (', '.join(sorted(g_dTargetEnvs.keys())),));
1308 oParser.add_option('--test-size', dest = 'sTestSize', default = InstructionTestGen.ksTestSize_Medium,
1309 choices = InstructionTestGen.kasTestSizes,
1310 help = 'Selects the test size.');
1311
1312 (oOptions, asArgs) = oParser.parse_args();
1313 if len(asArgs) > 0:
1314 oParser.print_help();
1315 return RTEXITCODE_SYNTAX
1316 if oOptions.sOutputBase is None:
1317 print('syntax error: Missing required option --output-base.', file = sys.stderr);
1318 return RTEXITCODE_SYNTAX
1319
1320 #
1321 # Instantiate the program class and run it.
1322 #
1323 oProgram = InstructionTestGen(oOptions);
1324 return oProgram.run();
1325
1326
1327if __name__ == '__main__':
1328 sys.exit(InstructionTestGen.main());
1329
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