VirtualBox

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

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