InstructionTestGen.py revision 54ed927d658674ced4387afbd1877a27cb975a76
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync# -*- coding: utf-8 -*-
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsyncInstruction Test Generator.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsyncCopyright (C) 2012-2013 Oracle Corporation
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsyncOracle Corporation confidential
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsyncAll rights reserved
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync# pylint: disable=C0103,R0913
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync# Standard python imports.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync## @name Exit codes
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync## @name Various C macros we're used to.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ 32-bit one bit mask. """
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync """ 64-bit one bit mask. """
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync## @name ModR/M
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync## @name SIB
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync## @name Prefixes
0c94a8282c9042b02f022302a3d987746140eab9vboxsync## @name General registers
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync## @name Register names.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs64NoSp = ('rax', 'rcx', 'rdx', 'rbx', None, 'rbp', 'rsi', 'rdi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs64 = ('rax', 'rcx', 'rdx', 'rbx', 'rsp', 'rbp', 'rsi', 'rdi', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs32NoSp = ('eax', 'ecx', 'edx', 'ebx', None, 'ebp', 'esi', 'edi',
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs32 = ('eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi',
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs16NoSp = ('ax', 'cx', 'dx', 'bx', None, 'bp', 'si', 'di',
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs16 = ('ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di',
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs8 = ('al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_asGRegs8Rex = ('al', 'cl', 'dl', 'bl', 'spl', 'bpl', 'sil', 'dil',
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b',
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync## @name Random
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncg_iMyRandSeed = int((os.urandom(4)).encode('hex'), 16);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#g_iMyRandSeed = 286523426;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#g_iMyRandSeed = 1994382324;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#g_oMyRand = random.SystemRandom();
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Unsigned 8-bit random number. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Unsigned 16-bit random number. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Unsigned 32-bit random number. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Unsigned 64-bit random number. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Unsigned 8-, 16-, 32-, or 64-bit random number. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Signed 8-, 16-, 32-, or 64-bit random number. """
0c94a8282c9042b02f022302a3d987746140eab9vboxsync """ List of unsigned 8-, 16-, 32-, or 64-bit random numbers. """
0c94a8282c9042b02f022302a3d987746140eab9vboxsync## @name Instruction Emitter Helpers
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncdef calcRexPrefixForTwoModRmRegs(iReg, iRm, bOtherRexPrefixes = 0):
0c94a8282c9042b02f022302a3d987746140eab9vboxsync Calculates a rex prefix if neccessary given the two registers
0c94a8282c9042b02f022302a3d987746140eab9vboxsync and optional rex size prefixes.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync Returns an empty array if not necessary.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Calculate the RM byte for two registers.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Returns an array with one byte in it.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync | ((iReg << X86_MODRM_REG_SHIFT) & X86_MODRM_REG_MASK) \
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync## @name Misc
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Converts a 32-bit unsigned value to 32-bit signed. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Rotate a xx-bit wide unsigned number to the left. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Rotate a xx-bit wide unsigned number to the right. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Gets the name of a general register by index and width. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Target Runtime Environment.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync ## @name CPU Modes
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync ## @name Instruction set.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.asGRegs = g_asGRegs64 if self.is64Bit() else g_asGRegs32;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.asGRegsNoSp = g_asGRegs64NoSp if self.is64Bit() else g_asGRegs32NoSp;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Whether it's an IPRT environment or not. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Whether it's a 64-bit environment or not. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Get the default operand size as a bit count. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Get the default operand size as a byte count. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Get the max operand size as a bit count. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Get the max operand size as a byte count. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Get the default address size as a bit count. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Get the default address size as a byte count. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Get the number of general registers. """
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync """ Returns a random general register number, excluding the SP register. """
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync def randGRegNoSpList(self, cItems, cbEffBytes = 4):
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync """ List of randGRegNoSp values. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Gets a list of addressing mode (16, 32, or/and 64). """
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync """ Checks if the given register is a high 8-bit general register (AH, CH, DH or BH). """
0c94a8282c9042b02f022302a3d987746140eab9vboxsync## Target environments.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync 'iprt-r3-32': TargetEnv('iprt-r3-32', TargetEnv.ksInstrSet_32, TargetEnv.ksCpuMode_Protect, 3),
0c94a8282c9042b02f022302a3d987746140eab9vboxsync 'iprt-r3-64': TargetEnv('iprt-r3-64', TargetEnv.ksInstrSet_64, TargetEnv.ksCpuMode_Long, 3),
0c94a8282c9042b02f022302a3d987746140eab9vboxsync 'bs2-r0-64': TargetEnv('bs2-r0-64', TargetEnv.ksInstrSet_64, TargetEnv.ksCpuMode_Long, 0),
0c94a8282c9042b02f022302a3d987746140eab9vboxsync Base class for testing one instruction.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync self.sInstr = sInstr if sInstr else sName.split()[0];
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync Tests if the instruction test is applicable to the selected environment.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync Emits the test assembly code.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(';; @todo not implemented. This is for the linter: %s, %s\n' % (oGen, sTestFnName));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync def generateInputs(self, cbEffOp, cbMaxOp, oGen, fLong = False):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Generate a list of inputs. """
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync # Try do extremes as well as different ranges of random numbers.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync auRet += [ UINT8_MAX / 2, UINT8_MAX / 2 + 1, UINT8_MAX ];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync auRet += [ UINT16_MAX / 2, UINT16_MAX / 2 + 1, UINT16_MAX ];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync auRet += [ UINT32_MAX / 2, UINT32_MAX / 2 + 1, UINT32_MAX ];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync auRet += [ UINT64_MAX / 2, UINT64_MAX / 2 + 1, UINT64_MAX ];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync for cBits, cValues in ( (8, 4), (16, 4), (32, 8), (64, 8) ):
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync elif oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync for cBits, cValues in ( (8, 8), (16, 8), (24, 2), (32, 16), (40, 1), (48, 1), (56, 1), (64, 16) ):
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync for cBits, cValues in ( (8, 16), (16, 16), (24, 4), (32, 64), (40, 4), (48, 4), (56, 4), (64, 64) ):
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync auRet += randUxxList(cbEffOp * 8, cWanted - len(auRet));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # Short list, just do some random numbers.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync elif oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Instruction reading memory or general register and writing the result to a
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync general register.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync def __init__(self, sName, fnCalcResult, sInstr = None, acbOpVars = None):
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync self.acbOpVars = [ 1, 2, 4, 8 ] if not acbOpVars else list(acbOpVars);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync ## @name Test Instruction Writers
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Writes the instruction with two general registers as operands. """
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync % (self.sInstr, gregName(iOp1, cbEffOp * 8, fRexByteRegs), gregName(iOp2, cbEffOp * 8, fRexByteRegs),));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync def writeInstrGregPureRM(self, cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen):
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync """ Writes the instruction with two general registers as operands. """
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync oGen.write('altrexb '); # Alternative encoding for rip relative addressing.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync oGen.write('%s %s, [' % (self.sInstr, g_asGRegs64[iOp1],));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync oGen.write('%s %s, [' % (self.sInstr, g_asGRegs32[iOp1],));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync oGen.write('%s %s, [' % (self.sInstr, g_asGRegs16[iOp1],));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync oGen.write('%s %s, [' % (self.sInstr, g_asGRegs8Rex[iOp1],));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write('VBINSTST_NAME(g_u%sData)' % (cbEffOp * 8,))
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync assert False; ## @todo implement 16-bit addressing.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync def writeInstrGregSibLabel(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Writes the instruction taking a register and a label (base only w/o reg), SIB form. """
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync assert offDisp is None; assert iBaseReg in [5, 13]; assert iIndexReg == 4; assert cAddrBits != 16;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # Note! Cannot test this in 64-bit mode in any sensible way because the disp is 32-bit
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # and we cannot (yet) make assumtions about where we're loaded.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync ## @todo Enable testing this in environments where we can make assumptions (boot sector).
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' %s %s, [VBINSTST_NAME(g_u%sData) xWrtRIP]\n'
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync % ( self.sInstr, gregName(iOp1, cbEffOp * 8), cbEffOp * 8,));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' altsibx%u %s %s, [VBINSTST_NAME(g_u%sData) xWrtRIP]\n'
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync % ( iScale, self.sInstr, gregName(iOp1, cbEffOp * 8), cbEffOp * 8,));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync def writeInstrGregSibScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
0c94a8282c9042b02f022302a3d987746140eab9vboxsync """ Writes the instruction taking a register and disp+scaled register (no base reg), SIB form. """
0c94a8282c9042b02f022302a3d987746140eab9vboxsync assert iBaseReg in [5, 13]; assert iIndexReg != 4; assert cAddrBits != 16;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync # Note! Using altsibxN to force scaled encoding. This is only really a
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync # necessity for iScale=1, but doesn't hurt for the rest.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync % (iScale, self.sInstr, gregName(iOp1, cbEffOp * 8), gregName(iIndexReg, cAddrBits), iScale,));
0c94a8282c9042b02f022302a3d987746140eab9vboxsync if offDisp is not None:
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync def writeInstrGregSibBase(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Writes the instruction taking a register and base only (with reg), SIB form. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync % (iScale, self.sInstr, gregName(iOp1, cbEffOp * 8), gregName(iBaseReg, cAddrBits),));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if offDisp is not None:
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync def writeInstrGregSibBaseAndScaledReg(self, cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Writes tinstruction taking a register and full featured SIB form address. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # Note! From the looks of things, yasm will encode the following instructions the same way:
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # mov eax, [rsi*1 + rbx]
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # mov eax, [rbx + rsi*1]
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # So, when there are two registers involved, the '*1' selects
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync # which is index and which is base.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync gregName(iBaseReg, cAddrBits), gregName(iIndexReg, cAddrBits), iScale,));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if offDisp is not None:
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync ## @name Memory setups
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync def generateMemSetupReadByLabel(self, oGen, cbEffOp, uInput):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Sets up memory for a memory read. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync def generateMemSetupReadByReg(self, oGen, cAddrBits, cbEffOp, iReg1, uInput, offDisp = None):
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Sets up memory for a memory read indirectly addressed thru one register and optional displacement. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iBaseReg = iReg1, offDisp = offDisp),));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iReg1],));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync def generateMemSetupReadByScaledReg(self, oGen, cAddrBits, cbEffOp, iIndexReg, iScale, uInput, offDisp = None):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Sets up memory for a memory read indirectly addressed thru one register and optional displacement. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, offDisp = offDisp, iIndexReg = iIndexReg, iScale = iScale),));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iIndexReg],));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync def generateMemSetupReadByBaseAndScaledReg(self, oGen, cAddrBits, cbEffOp, iBaseReg, iIndexReg, iScale, uInput, offDisp):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Sets up memory for a memory read indirectly addressed thru two registers with optional displacement. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iBaseReg = iBaseReg, offDisp = offDisp,
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iIndexReg],));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iBaseReg],));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync def generateMemSetupPureRM(self, oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp = None):
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync """ Sets up memory for a pure R/M addressed read, iOp2 being the R/M value. """
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync % (oGen.needGRegMemSetup(cAddrBits, cbEffOp, iOp2, offDisp),));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.write(' call VBINSTST_NAME(Common_SetupMemReadU%u)\n' % (cbEffOp*8,));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync def generateOneStdTestGregGreg(self, oGen, cbEffOp, cbMaxOp, iOp1, iOp1X, iOp2, iOp2X, uInput, uResult):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync """ Generate one standard instr greg,greg test. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uInput,));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync self.writeInstrGregGreg(cbEffOp, iOp1, iOp2, oGen);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1X, iOp2X if iOp1X != iOp2X else None),));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync def generateOneStdTestGregGreg8BitHighPain(self, oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput):
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync """ High 8-bit registers are a real pain! """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync assert oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) or oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync # Figure out the register indexes of the max op sized regs involved.
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync oGen.write(' ; iOp1=%u iOp1X=%u iOp2=%u iOp2X=%u\n' % (iOp1, iOp1X, iOp2, iOp2X,));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # Calculate unshifted result.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) != oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync uResult = self.fnCalcResult(cbEffOp, uInput, uCur, oGen);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync # Rotate the input and/or result to match their max-op-sized registers.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync # Hand it over to an overridable worker method.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync return self.generateOneStdTestGregGreg(oGen, cbEffOp, cbMaxOp, iOp1, iOp1X, iOp2, iOp2X, uInput, uResult);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync def generateOneStdTestGregMemNoSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iOp2, uInput, uResult):
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Generate mode 0, 1 and 2 test for the R/M=iOp2. """
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, None, oGen);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.generateMemSetupPureRM(oGen, cAddrBits, cbEffOp, iOp2, iMod, uInput, offDisp);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.writeInstrGregPureRM(cbEffOp, iOp1, cAddrBits, iOp2, iMod, offDisp, oGen);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(iOp1, iOp2),));
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync def generateOneStdTestGregMemSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod, # pylint: disable=R0913
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Generate one SIB variations. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if ((iBaseReg == 5 or iBaseReg == 13) and iMod == 0):
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync continue; # skipping.
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.generateMemSetupReadByLabel(oGen, cbEffOp, uInput);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.writeInstrGregSibLabel(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.generateMemSetupReadByScaledReg(oGen, cAddrBits, cbEffOp, iIndexReg, iScale, uInput, offDisp);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.writeInstrGregSibScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.generateMemSetupReadByReg(oGen, cAddrBits, cbEffOp, iBaseReg, uInput, offDisp);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.writeInstrGregSibBase(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if iIndexReg == iBaseReg and iScale == 1 and offDisp is not None and (offDisp & 1):
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.generateMemSetupReadByBaseAndScaledReg(oGen, cAddrBits, cbEffOp, iBaseReg,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync self.writeInstrGregSibBaseAndScaledReg(cbEffOp, iOp1, cAddrBits, iBaseReg, iIndexReg, iScale, offDisp, oGen);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync sChecker = oGen.needGRegChecker(iOp1, iBaseReg, iIndexReg);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.write(' call VBINSTST_NAME(%s)\n' % (sChecker,));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync def generateStdTestGregMemSib(self, oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, auInputs):
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Generate all SIB variations for the given iOp1 (reg) value. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync while i > 0:
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync oGen.iSibBaseReg = (oGen.iSibBaseReg + 1) % oGen.oTarget.getGRegCount(cAddrBits / 8);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if oGen.iSibBaseReg == X86_GREG_xSP: # no RSP testing atm.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync while j > 0:
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync oGen.iSibIndexReg = (oGen.iSibIndexReg + 1) % oGen.oTarget.getGRegCount(cAddrBits / 8);
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync if oGen.iSibIndexReg == iOp1 and oGen.iSibIndexReg != 4 and cAddrBits != cbMaxOp:
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync continue; # Don't know the high bit of the address ending up the result - skip it for now.
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync and ((oGen.iSibBaseReg != 5 and oGen.iSibBaseReg != 13) or iMod != 0) \
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync continue; # Don't know the high bit of the address ending up the result - skip it for now.
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[iOp1], oGen);
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync self.generateOneStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, iOp1, iMod,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync oGen.iSibBaseReg, oGen.iSibIndexReg, oGen.iSibScale,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync """ Generate standard tests. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync # Parameters.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync auShortInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync auLongInputs = self.generateInputs(cbDefOp, cbMaxOp, oGen, fLong = True);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Register tests
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oOp2Range = range(oGen.oTarget.getGRegCount(cbEffOp));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for iOp1 in range(oGen.oTarget.getGRegCount(cbEffOp)):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync continue; # Cannot test xSP atm.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync continue; # Any REX encoding turns AH,CH,DH,BH regs into SPL,BPL,SIL,DIL.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync continue; # Cannot test xSP atm.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write('; iOp2=%u cbEffOp=%u\n' % (iOp2, cbEffOp));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for uInput in (auLongInputs if iOp1 == iLongOp1 and iOp2 == iLongOp2 else auShortInputs):
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if not oGen.oTarget.is8BitHighGReg(cbEffOp, iOp1) and not oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2):
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync uCur = oGen.auRegValues[iOp1 & 15] if iOp1 != iOp2 else uInput;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync uResult = self.fnCalcResult(cbEffOp, uInput, uCur, oGen);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync self.generateOneStdTestGregGreg(oGen, cbEffOp, cbMaxOp, iOp1, iOp1 & 15, iOp2, iOp2 & 15,
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync self.generateOneStdTestGregGreg8BitHighPain(oGen, cbEffOp, cbMaxOp, iOp1, iOp2, uInput);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync # Memory test.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.iModReg = (oGen.iModReg + 1) % oGen.oTarget.getGRegCount(cbEffOp);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync continue; # Cannot test xSP atm.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync continue; ## TODO AH,CH,DH,BH
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync auInputs = auLongInputs if oGen.iModReg == iLongOp1 else auShortInputs;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.iModRm = (oGen.iModRm + 1) % oGen.oTarget.getGRegCount(cAddrBits * 8);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if oGen.iModReg == oGen.iModRm and oGen.iModRm != 5 \
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync continue; # Don't know the high bit of the address ending up the result - skip it for now.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[oGen.iModReg & 15], oGen);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync self.generateOneStdTestGregMemNoSib(oGen, cAddrBits, cbEffOp, cbMaxOp,
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync # SIB - currently only short list of inputs or things may get seriously out of hand.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync self.generateStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, oGen.iModReg, auShortInputs);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.write('VBINSTST_BEGINPROC %s\n' % (sTestFnName,));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync #oGen.write(' int3\n');
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync #oGen.write(' int3\n');
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.write('VBINSTST_ENDPROC %s\n' % (sTestFnName,));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncclass InstrTest_Mov_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync Tests MOV Gv,Ev.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync InstrTest_MemOrGreg_2_Greg.__init__(self, 'mov Gv,Ev', self.calc_mov);
38745c55f37c31ba8b78cc728d2f08ea6eec38d6vboxsync """ Calculates the result of a mov instruction."""
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return (uCur & 0xffffffffffff0000) | (uInput & UINT16_MAX);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return (uCur & 0xffffffffffffff00) | (uInput & UINT8_MAX);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncclass InstrTest_MovSxD_Gv_Ev(InstrTest_MemOrGreg_2_Greg):
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync Tests MOVSXD Gv,Ev.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync InstrTest_MemOrGreg_2_Greg.__init__(self, 'movsxd Gv,Ev', self.calc_movsxd, acbOpVars = [ 8, 4, 2, ]);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync def writeInstrGregGreg(self, cbEffOp, iOp1, iOp2, oGen):
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync oGen.write(' %s %s, %s\n' % (self.sInstr, g_asGRegs64[iOp1], g_asGRegs32[iOp2]));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync abInstr += calcRexPrefixForTwoModRmRegs(iOp1, iOp2);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync Calculates the result of a movxsd instruction.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync Returns the result value (cbMaxOp sized).
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return (uCur & 0xffffffffffff0000) | (uInput & 0xffff);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync Tests IDIV and DIV instructions.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync InstrTestBase.__init__(self, 'idiv Gv,Ev', 'idiv');
e70bda5438c3582164d26f171a8bc8d3d7da1e12vboxsync def generateInputsNoXcpt(self, cbEffOp, fLong = False):
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync """ Generate inputs for cbEffOp. Returns a list of pairs, dividen + divisor. """
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync # Test params.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync # edge tests
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync auRet.append([-(uDividend + uDivisor - 1), uDivisor]);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync auRet.append([ (uDividend + uDivisor - 1), -uDivisor]);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync auRet.append([uDivisor * (uDivisor - 1) - 1, uDivisor]);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync auRet.append([-(uDivisor * (uDivisor + 1) - 1), uDivisor]);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync # random tests.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if uDivisor == 0 or uDivisor >= uStep or uDivisor < -uStep:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if uResult >= uStep or uResult <= -uStep: # exclude difficulties
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync def generateOneStdTestGreg(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Generate code of one '[I]DIV rDX:rAX,<GREG>' test. """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if iReminder != 0 and iQuotient < 0: # python has different rounding rules for negative division.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' ; iQuotient=%#x (%d) iReminder=%#x (%d)\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync % ( iDividend & fFullOp1, iDividend, iDivisor & fEffOp, iDivisor,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync iQuotient & fEffOp, iQuotient, iReminder & fEffOp, iReminder, ));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xDX], uDX,));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2], uOp2Val,));
8f7ee9e453c60b3b699799538a45950b35266665vboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2],));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write(' %-4s %s\n' % (self.sInstr, gregName(iOp2, cbEffOp * 8),));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, X86_GREG_xDX, iOp2),));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync def generateOneStdTestGreg8Bit(self, oGen, cbEffOp, iOp2, iDividend, iDivisor):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync """ Generate code of one '[I]DIV AX,<GREG>' test (8-bit). """
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync fMaxOp = UINT64_MAX if cbMaxOp == 8 else UINT32_MAX; assert cbMaxOp in [8, 4];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync iOp2X = (iOp2 & 3) if oGen.oTarget.is8BitHighGReg(cbEffOp, iOp2) else iOp2;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if iReminder != 0 and iQuotient < 0: # python has different rounding rules for negative division.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync uAXResult = (iQuotient & UINT8_MAX) | ((iReminder & UINT8_MAX) << 8);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync uAX |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT16_MAX);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync uOp2Val |= randUxx(cbMaxOp * 8) & (fMaxOp - UINT8_MAX);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync oGen.write(' ; iDividend=%#x (%d) iDivisor=%#x (%d)\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ' ; iQuotient=%#x (%d) iReminder=%#x (%d)\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync % ( iDividend & UINT16_MAX, iDividend, iDivisor & UINT8_MAX, iDivisor,
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync iQuotient & UINT8_MAX, iQuotient, iReminder & UINT8_MAX, iReminder, ));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync oGen.write(' call VBINSTST_NAME(Common_LoadKnownValues)\n');
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[X86_GREG_xAX], uAX,));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync oGen.write(' mov %s, 0x%x\n' % (oGen.oTarget.asGRegs[iOp2X], uOp2Val,));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync oGen.write(' push %s\n' % (oGen.oTarget.asGRegs[iOp2X],));
8f7ee9e453c60b3b699799538a45950b35266665vboxsync oGen.write(' %-4s %s\n' % (self.sInstr, gregName(iOp2, cbEffOp * 8),));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync oGen.write(' call VBINSTST_NAME(%s)\n' % (oGen.needGRegChecker(X86_GREG_xAX, iOp2X),));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync """ Generates test that causes no exceptions. """
38745c55f37c31ba8b78cc728d2f08ea6eec38d6vboxsync # Parameters.
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync # Register tests
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync oOp2Range = range(oGen.oTarget.getGRegCount(cbEffOp));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if oGen.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync continue; # Cannot test xSP atm.
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if iOp2 == X86_GREG_xAX or (cbEffOp > 1 and iOp2 == X86_GREG_xDX):
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync continue; # Will overflow or be too complicated to get right.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if cbEffOp == 1 and iOp2 == (16 if oGen.oTarget.is64Bit() else 4):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync continue; # Avoid dividing by AH, same reasons as above.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for iDividend, iDivisor in self.generateInputsNoXcpt(cbEffOp, iOp2 == iLongOp2):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.generateOneStdTestGreg(oGen, cbEffOp, iOp2, iDividend, iDivisor);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.generateOneStdTestGreg8Bit(oGen, cbEffOp, iOp2, iDividend, iDivisor);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ## Memory test.
38745c55f37c31ba8b78cc728d2f08ea6eec38d6vboxsync # for cAddrBits in oGen.oTarget.getAddrModes():
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # for cbEffOp in self.acbOpVars:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # if cbEffOp > cbMaxOp:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # continue;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # auInputs = auLongInputs if oGen.iModReg == iLongOp1 else auShortInputs;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # for _ in oGen.oModRmRange:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # oGen.iModRm = (oGen.iModRm + 1) % oGen.oTarget.getGRegCount(cAddrBits * 8);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # if oGen.iModRm != 4 or cAddrBits == 16:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # for uInput in auInputs:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # oGen.newSubTest();
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # if oGen.iModReg == oGen.iModRm and oGen.iModRm != 5 and oGen.iModRm != 13 and cbEffOp != cbMaxOp:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # continue; # Don't know the high bit of the address ending up the result - skip it for now.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # uResult = self.fnCalcResult(cbEffOp, uInput, oGen.auRegValues[oGen.iModReg & 15], oGen);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # self.generateOneStdTestGregMemNoSib(oGen, cAddrBits, cbEffOp, cbMaxOp,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # oGen.iModReg, oGen.iModRm, uInput, uResult);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # # SIB - currently only short list of inputs or things may get seriously out of hand.
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync # self.generateStdTestGregMemSib(oGen, cAddrBits, cbEffOp, cbMaxOp, oGen.iModReg, auShortInputs);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync oGen.write('VBINSTST_BEGINPROC %s\n' % (sTestFnName,));
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync #oGen.write(' int3\n');
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync #oGen.write(' int3\n');
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync oGen.write('VBINSTST_ENDPROC %s\n' % (sTestFnName,));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync# Instruction Tests.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync #InstrTest_MovSxD_Gv_Ev(),
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncclass InstructionTestGen(object): # pylint: disable=R0902
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync Instruction Test Generator.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ## @name Test size
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync kasTestSizes = ( ksTestSize_Large, ksTestSize_Medium, ksTestSize_Tiny );
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Calculate the number of output files.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if len(g_aoInstructionTests) > self.oOptions.cInstrPerFile:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.cFiles = len(g_aoInstructionTests) / self.oOptions.cInstrPerFile;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if self.cFiles * self.oOptions.cInstrPerFile < len(g_aoInstructionTests):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Fix the known register values.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.au32Regs = [(self.au64Regs[i] & UINT32_MAX) for i in range(8)];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.au16Regs = [(self.au64Regs[i] & UINT16_MAX) for i in range(8)];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.auRegValues = self.au64Regs if self.oTarget.is64Bit() else self.au32Regs;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Declare state variables used while generating.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # State variables used while generating test convenientely placed here (lazy bird)...
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Tiny:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync elif self.oOptions.sTestSize == InstructionTestGen.ksTestSize_Medium:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self._oModRegRange = range( 5 if self.oTarget.is64Bit() else 4);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync self._oModRegRange8 = range( 6 if self.oTarget.is64Bit() else 4);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync self._oModRegRange = range(16 if self.oTarget.is64Bit() else 8);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync self._oModRegRange8 = range(20 if self.oTarget.is64Bit() else 8);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync self.oModRmRange = range(16 if self.oTarget.is64Bit() else 8);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync # Methods used by instruction tests.
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync """ Writes to the current output file. """
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync """ Writes a line to the current output file. """
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync Emits an instruction given as a sequence of bytes values.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Indicates that a new subtest has started.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' mov dword [VBINSTST_NAME(g_uVBInsTstSubTestIndicator) xWrtRIP], __LINE__\n');
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync def needGRegChecker(self, iReg1, iReg2 = None, iReg3 = None):
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Records the need for a given register checker function, returning its label.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if iReg2 is not None:
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if iReg3 is not None:
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync sName = '%s_%s_%s' % (self.oTarget.asGRegs[iReg1], self.oTarget.asGRegs[iReg2], self.oTarget.asGRegs[iReg3],);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync sName = '%s_%s' % (self.oTarget.asGRegs[iReg1], self.oTarget.asGRegs[iReg2],);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync assert iReg3 is None;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync def needGRegMemSetup(self, cAddrBits, cbEffOp, iBaseReg = None, offDisp = None, iIndexReg = None, iScale = 1):
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Records the need for a given register checker function, returning its label.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if iBaseReg is not None:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if iIndexReg is not None:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync sName += '_%s' % (gregName(iIndexReg, cAddrBits),);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if offDisp is not None:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync Records the need for a 64-bit constant, returning its label.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync These constants are pooled to attempt reduce the size of the whole thing.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Emits a push constant value, taking care of high values on 64-bit hosts.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if self.oTarget.is64Bit() and uResult >= 0x80000000:
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' push qword [%s wrt rip]\n' % (self.need64BitConstant(uResult),));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Get a set of address dispositions for a given addressing mode.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync The alignment restriction is for SIB scaling.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync aoffDisp = [ None, ];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync aoffDisp = [ 2147483647 & ~(cbAlignment - 1), -2147483648 ];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync else: assert False;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync The Mod R/M register range varies with the effective operand size, for
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 8-bit registers we have 4 more.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync We vary the SIB index test range a little to try cover more operand
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync combinations and avoid repeating the same ones.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Internal machinery.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Initializes the Mod R/M and SIB state index with random numbers prior
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync to generating a test.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Note! As with all other randomness and variations we do, we cannot
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync test all combinations for each and every instruction so we try
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync get coverage over time.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync def _calcTestFunctionName(self, oInstrTest, iInstrTest):
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Calc a test function name for the given instruction test.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync sName = 'TestInstr%03u_%s' % (iInstrTest, oInstrTest.sName);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return sName.replace(',', '_').replace(' ', '_').replace('%', '_');
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Writes the file header.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Raises exception on trouble.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ';; @file %s\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '; Autogenerate by %s %s. DO NOT EDIT\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '; Headers\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '%%include "env-%s.mac"\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Target environment specific init stuff.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Global variables.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '; Globals\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_GLOBALNAME_EX g_pvLow16Mem4K, data hidden\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_GLOBALNAME_EX g_pvLow32Mem4K, data hidden\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_GLOBALNAME_EX g_pvMem4K, data hidden\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_GLOBALNAME_EX g_uVBInsTstSubTestIndicator, data hidden\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_BEGINCODE\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write('g_u64KnownValue_%s: dq 0x%x\n' % (g_asGRegs64[i], self.au64Regs[i]));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Common functions.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Loading common values.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_BEGINPROC Common_LoadKnownValues\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '%ifdef RT_ARCH_AMD64\n');
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' mov %s, 0x%x\n' % (g_asGRegs64NoSp[i], self.au64Regs[i],));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync self.write(' mov %s, 0x%x\n' % (g_asGRegs32NoSp[i], self.au32Regs[i],));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_ENDPROC Common_LoadKnownValues\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write('VBINSTST_BEGINPROC Common_CheckKnownValues\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '%ifdef RT_ARCH_AMD64\n');
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' cmp %s, [g_u64KnownValue_%s wrt rip]\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' je .ok_%u\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' push %u ; register number\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' push %s ; actual\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' push qword [g_u64KnownValue_%s wrt rip] ; expected\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' call VBINSTST_NAME(Common_BadValue)\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '.ok_%u:\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync % ( g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i, i, g_asGRegs64NoSp[i], g_asGRegs64NoSp[i], i,));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' je .ok_%u\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' push %u ; register number\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' push %s ; actual\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' push dword 0x%x ; expected\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' call VBINSTST_NAME(Common_BadValue)\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync '.ok_%u:\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync % ( g_asGRegs32NoSp[i], self.au32Regs[i], i, i, g_asGRegs32NoSp[i], self.au32Regs[i], i,));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_ENDPROC Common_CheckKnownValues\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync def _generateMemSetupFunctions(self): # pylint: disable=R0915
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Generates the memory setup functions.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Unpack it.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cAddrBits = int(asParams[0][:-3]); assert asParams[0][-3:] == 'bit';
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cEffOpBits = int(asParams[1][1:]); assert asParams[1][0] == 'U';
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if i < len(asParams) and asParams[i] in asAddrGRegs:
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync assert i < len(asParams); assert asParams[i][0] == 'x';
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync iScale = iScale = int(asParams[i][1:]); assert iScale in [1, 2, 4, 8], '%u %s' % (iScale, sName);
8f7ee9e453c60b3b699799538a45950b35266665vboxsync if i < len(asParams) and asParams[i] in asAddrGRegs:
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync assert i == len(asParams), 'i=%d len=%d len[i]=%d (%s)' % (i, len(asParams), len(asParams[i]), asParams[i],);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync # Find a temporary register.
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync # Prologue.
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync '; cAddrBits=%s cEffOpBits=%s iBaseReg=%s u32Disp=%s iIndexReg=%s iScale=%s\n'
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync 'VBINSTST_BEGINPROC Common_MemSetup_%s\n'
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync ' MY_PUSH_FLAGS\n'
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync ' push %s\n'
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync % ( cAddrBits, cEffOpBits, iBaseReg, u32Disp, iIndexReg, iScale,
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync # Figure out what to use.
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync # Special case: reg + reg * [2,4,8]
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if iBaseReg == iIndexReg and iBaseReg is not None and iScale != 1:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ' push %s\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ' push sDX\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.write(' mov %s, [VBINSTST_NAME(g_pvLow16Mem4K) xWrtRIP]\n' % (sTmpReg2,));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' mov %s, [VBINSTST_NAME(g_pvLow32Mem4K) xWrtRIP]\n' % (sTmpReg2,));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync self.write(' mov %s, %s\n' % (gregName(X86_GREG_xAX, cAddrBits), sTmpReg2,));
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync if u32Disp is not None:
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync self.write(' sub %s, %d\n' % ( gregName(X86_GREG_xAX, cAddrBits), convU32ToSigned(u32Disp), ));
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync '%if xCB == 2\n'
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync ' push 0\n'
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync '%endif\n');
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.write(' div %s [xSP]\n' % ('qword' if cAddrBits == 64 else 'dword',));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' sub %s, %s\n' % (sTmpReg2, gregName(X86_GREG_xDX, cAddrBits),));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' pop sDX\n'); # sTmpReg2 is eff address; sAX is sIndexReg value.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Note! sTmpReg1 can be xDX and that's no problem now.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync self.write(' mov %s, [xSP + sCB*3 + MY_PUSH_FLAGS_SIZE + xCB]\n' % (sTmpReg1,));
0c94a8282c9042b02f022302a3d987746140eab9vboxsync self.write(' mov [%s], %s\n' % (sTmpReg2, sTmpReg1,)); # Value in place.
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.write(' pop %s\n' % (self.oTarget.asGRegs[iTmpReg2],));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.write(' pop %s\n' % (self.oTarget.asGRegs[iTmpReg1],));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.write(' mov %s, %s\n' % (sBaseReg, gregName(X86_GREG_xAX, cAddrBits),));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Load the value and mem address, storing the value there.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Note! ASSUMES that the scale and disposition works fine together.
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync sAddrReg = sBaseReg if sBaseReg is not None else sIndexReg;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' mov %s, [xSP + sCB + MY_PUSH_FLAGS_SIZE + xCB]\n' % (sTmpReg1,));
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync self.write(' mov [%s xWrtRIP], %s\n' % (sDataVar, sTmpReg1,));
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync self.write(' lea %s, [%s xWrtRIP]\n' % (sAddrReg, sDataVar,));
0c94a8282c9042b02f022302a3d987746140eab9vboxsync self.write(' mov %s, [VBINSTST_NAME(g_pvLow16Mem4K) xWrtRIP]\n' % (sAddrReg,));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' mov %s, [VBINSTST_NAME(g_pvLow32Mem4K) xWrtRIP]\n' % (sAddrReg,));
0c94a8282c9042b02f022302a3d987746140eab9vboxsync self.write(' add %s, %s\n' % (sAddrReg, (randU16() << cEffOpBits) & 0xfff, ));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.write(' mov [%s], %s\n' % (sAddrReg, sTmpReg1, ));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync # Adjust for disposition and scaling.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if u32Disp is not None:
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write(' sub %s, %d\n' % ( sAddrReg, convU32ToSigned(u32Disp), ));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if iIndexReg is not None:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync elif sBaseReg is not None:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ' sub %s, %s\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ' mov %s, %u\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' sub %s, %#06x\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync % ( sIndexReg, uIdxRegVal, sBaseReg, (uIdxRegVal * iScale) & UINT32_MAX, ));
0c94a8282c9042b02f022302a3d987746140eab9vboxsync # Set upper bits that's supposed to be unused.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync if iBaseReg is not None:
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' or %s, %s\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if iIndexReg is not None and iIndexReg != iBaseReg:
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ' or %s, %s\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync % ( g_asGRegs64[iTmpReg1], randU64() & 0xffffffff00000000,
0c94a8282c9042b02f022302a3d987746140eab9vboxsync assert cDefAddrBits == 32; assert cAddrBits == 16; assert iIndexReg is None;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync if iBaseReg is not None:
0c94a8282c9042b02f022302a3d987746140eab9vboxsync % ( g_asGRegs32[iBaseReg], randU32() & 0xffff0000, ));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync # Epilogue.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' MY_POP_FLAGS\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ' ret sCB\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync 'VBINSTST_ENDPROC Common_MemSetup_%s\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync Generates file footer.
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync # Register checking functions.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync '; Checks 1 or more register values, expected values pushed on the stack.\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync '; To save space, the callee cleans up the stack.'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync '; Ref count: %u\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'VBINSTST_BEGINPROC Common_Check_%s\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' MY_PUSH_FLAGS\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Register checks.
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync if i == asRegs.index(sReg): # Only check once, i.e. input = output reg.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync self.write(' cmp %s, [xSP + MY_PUSH_FLAGS_SIZE + xCB + sCB * %u]\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' je .equal%u\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' push %s %u ; register number\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' push %s ; actual\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' mov %s, [xSP + sCB*2 + MY_PUSH_FLAGS_SIZE + xCB + sCB * %u]\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' push %s ; expected\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' call VBINSTST_NAME(Common_BadValue)\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync '.equal%u:\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync % ( sReg, i, i, sPushSize, iReg, sReg, sReg, i, sReg, i, ) );
0c94a8282c9042b02f022302a3d987746140eab9vboxsync # Restore known register values and check the other registers.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync self.write(' mov %s, [g_u64KnownValue_%s wrt rip]\n' % (sReg, sReg,));
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync self.write(' mov %s, 0x%x\n' % (sReg, self.au32Regs[iReg],));
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync ' call VBINSTST_NAME(Common_CheckKnownValues)\n'
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync ' ret sCB*%u\n'
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync 'VBINSTST_ENDPROC Common_Check_%s\n'
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync # memory setup functions
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync # 64-bit constants.
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync '; 64-bit constants\n'
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.write('g_u64Const_0x%016x: dq 0x%016x ; Ref count: %d\n' % (uVal, uVal, self._d64BitConsts[uVal], ) );
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync Generate the test cases.
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync self.sFile = '%s.asm' % (self.oOptions.sOutputBase,)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.sFile = '%s-%u.asm' % (self.oOptions.sOutputBase, self.iFile)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync self.oFile = io.open(self.sFile, 'w', buffering = 65536, encoding = 'utf-8');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Calc the range.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync iInstrTestStart = self.iFile * self.oOptions.cInstrPerFile;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync iInstrTestEnd = iInstrTestStart + self.oOptions.cInstrPerFile;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Generate the instruction tests.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oInstrTest.generateTest(self, self._calcTestFunctionName(oInstrTest, iInstrTest));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Generate the main function.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'VBINSTST_BEGINPROC TestInstrMain\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' MY_PUSH_ALL\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' sub xSP, 40h\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' lea rdi, [.szInstr%03u wrt rip]\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync '%%elifdef ASM_CALL64_MSC\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' lea rcx, [.szInstr%03u wrt rip]\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' mov xAX, .szInstr%03u\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ' mov [xSP], xAX\n'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync '%%endif\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' VBINSTST_CALL_FN_SUB_TEST\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' call VBINSTST_NAME(%s)\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync % ( iInstrTest, iInstrTest, iInstrTest, self._calcTestFunctionName(oInstrTest, iInstrTest)));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' add xSP, 40h\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' MY_POP_ALL\n'
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ' ret\n\n');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for iInstrTest in range(iInstrTestStart, iInstrTestEnd):
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync self.write('.szInstr%03u: db \'%s\', 0\n' % (iInstrTest, g_aoInstructionTests[iInstrTest].sName,));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync Generate a list of output files on standard output.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync print(' '.join('%s-%s.asm' % (self.oOptions.sOutputBase, i) for i in range(self.cFiles)));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Generates the tests or whatever is required.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync sys.stderr.write('InstructionTestGen.py: Seed = %s\n' % (g_iMyRandSeed,));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Main function a la C/C++. Returns exit code.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync # Parse the command line.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oParser = OptionParser(version = __version__[11:-1].strip());
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oParser.add_option('--makefile-mode', dest = 'fMakefileMode', action = 'store_true', default = False,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync help = 'Special mode for use to output a list of output files for the benefit of '
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 'the make program (kmk).');
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync oParser.add_option('--split', dest = 'cInstrPerFile', metavar = '<instr-per-file>', type = 'int', default = 9999999,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync help = 'Number of instruction to test per output file.');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oParser.add_option('--output-base', dest = 'sOutputBase', metavar = '<file>', default = None,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync help = 'The output file base name, no suffix please. Required.');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oParser.add_option('--target', dest = 'sTargetEnv', metavar = '<target>',
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync oParser.add_option('--test-size', dest = 'sTestSize', default = InstructionTestGen.ksTestSize_Medium,
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync print('syntax error: Missing required option --output-base.', file = sys.stderr);
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync # Instantiate the program class and run it.