VirtualBox

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

Last change on this file since 85416 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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

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