Changeset 108861 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Apr 5, 2025 1:15:03 AM (5 weeks ago)
- svn:sync-xref-src-repo-rev:
- 168311
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/target-armv8/bsd-spec-analyze.py
r108853 r108861 2 2 # -*- coding: utf-8 -*- 3 3 # $Id$ 4 # pylint: disable=invalid-name 4 5 5 6 """ … … 35 36 # Standard python imports. 36 37 import argparse; 37 import ast;38 38 import collections; 39 39 import datetime; … … 45 45 import tarfile; 46 46 import traceback; 47 import cProfile; 47 48 48 49 … … 56 57 """ 57 58 58 k TypeBinaryOp = 'AST.BinaryOp';59 k TypeBool = 'AST.Bool';60 k TypeConcat = 'AST.Concat';61 k TypeFunction = 'AST.Function';62 k TypeIdentifier = 'AST.Identifier';63 k TypeInteger = 'AST.Integer';64 k TypeSet = 'AST.Set';65 k TypeSquareOp = 'AST.SquareOp';66 k TypeUnaryOp = 'AST.UnaryOp';67 k TypeValue = 'Values.Value';59 ksTypeBinaryOp = 'AST.BinaryOp'; 60 ksTypeBool = 'AST.Bool'; 61 ksTypeConcat = 'AST.Concat'; 62 ksTypeFunction = 'AST.Function'; 63 ksTypeIdentifier = 'AST.Identifier'; 64 ksTypeInteger = 'AST.Integer'; 65 ksTypeSet = 'AST.Set'; 66 ksTypeSquareOp = 'AST.SquareOp'; 67 ksTypeUnaryOp = 'AST.UnaryOp'; 68 ksTypeValue = 'Values.Value'; 68 69 69 70 def __init__(self, sType): 70 71 self.sType = sType; 71 72 73 @staticmethod 72 74 def assertAttribsInSet(oJson, oAttribSet): 73 75 """ Checks that the JSON element has all the attributes in the set and nothing else. """ … … 135 137 136 138 kfnTypeMap = { 137 k TypeBinaryOp:fromJsonBinaryOp,138 k TypeUnaryOp:fromJsonUnaryOp,139 k TypeSquareOp:fromJsonSquareOp,140 k TypeConcat:fromJsonConcat,141 k TypeFunction:fromJsonFunction,142 k TypeIdentifier:fromJsonIdentifier,143 k TypeBool:fromJsonBool,144 k TypeInteger:fromJsonInteger,145 k TypeSet:fromJsonSet,146 k TypeValue:fromJsonValue,139 ksTypeBinaryOp: fromJsonBinaryOp, 140 ksTypeUnaryOp: fromJsonUnaryOp, 141 ksTypeSquareOp: fromJsonSquareOp, 142 ksTypeConcat: fromJsonConcat, 143 ksTypeFunction: fromJsonFunction, 144 ksTypeIdentifier: fromJsonIdentifier, 145 ksTypeBool: fromJsonBool, 146 ksTypeInteger: fromJsonInteger, 147 ksTypeSet: fromJsonSet, 148 ksTypeValue: fromJsonValue, 147 149 }; 148 150 … … 152 154 #print('debug ast: %s' % oJson['_type']) 153 155 return ArmAstBase.kfnTypeMap[oJson['_type']](oJson); 156 157 def isBoolAndTrue(self): 158 """ Check if this is a boolean with the value True. """ 159 #return isinstance(self, ArmAstBool) and self.fValue is True; 160 if isinstance(self, ArmAstBool): 161 return self.fValue is True; 162 return False; 154 163 155 164 … … 172 181 173 182 def __init__(self, oLeft, sOp, oRight): 174 ArmAstBase.__init__(self, ArmAstBase.k TypeBinaryOp);183 ArmAstBase.__init__(self, ArmAstBase.ksTypeBinaryOp); 175 184 assert sOp in ArmAstBinaryOp.kdOps, 'sOp="%s"' % (sOp,); 176 185 self.oLeft = oLeft; … … 180 189 # Switch value == field non-sense (simplifies transferConditionsToEncoding and such): 181 190 if ( isinstance(oRight, ArmAstIdentifier) 182 and isinstance(oLeft, [ArmAstValue, ArmAstInteger])191 and isinstance(oLeft, (ArmAstValue, ArmAstInteger)) 183 192 and sOp in ['==', '!=']): 184 193 self.oLeft = oRight; … … 210 219 211 220 def __init__(self, sOp, oExpr): 212 ArmAstBase.__init__(self, ArmAstBase.k TypeUnaryOp);221 ArmAstBase.__init__(self, ArmAstBase.ksTypeUnaryOp); 213 222 assert sOp in ArmAstUnaryOp.kdOps, 'sOp=%s' % (sOp,); 214 223 self.sOp = sOp; … … 221 230 222 231 class ArmAstSquareOp(ArmAstBase): 223 def __init__(self, aoValues): 224 ArmAstBase.__init__(self, ArmAstBase.kTypeSquareOp); 232 def __init__(self, oVar, aoValues): 233 ArmAstBase.__init__(self, ArmAstBase.ksTypeSquareOp); 234 self.oVar = oVar; 225 235 self.aoValues = aoValues; 226 236 227 237 def toString(self): 228 return ' <%s>' % (','.join([oValue.toString() for oValue in self.aoValues]),);238 return '%s<%s>' % (self.oVar.toString(), ','.join([oValue.toString() for oValue in self.aoValues]),); 229 239 230 240 231 241 class ArmAstConcat(ArmAstBase): 232 242 def __init__(self, aoValues): 233 ArmAstBase.__init__(self, ArmAstBase.k TypeConcat);243 ArmAstBase.__init__(self, ArmAstBase.ksTypeConcat); 234 244 self.aoValues = aoValues; 235 245 … … 249 259 250 260 def __init__(self, sName, aoArgs): 251 ArmAstBase.__init__(self, ArmAstBase.k TypeFunction);261 ArmAstBase.__init__(self, ArmAstBase.ksTypeFunction); 252 262 assert self.s_oReValidName.match(sName), 'sName=%s' % (sName); 253 263 self.sName = sName; … … 261 271 262 272 def __init__(self, sName): 263 ArmAstBase.__init__(self, ArmAstBase.k TypeIdentifier);273 ArmAstBase.__init__(self, ArmAstBase.ksTypeIdentifier); 264 274 assert self.s_oReValidName.match(sName), 'sName=%s' % (sName); 265 275 self.sName = sName; … … 270 280 class ArmAstBool(ArmAstBase): 271 281 def __init__(self, fValue): 272 ArmAstBase.__init__(self, ArmAstBase.k TypeBool);282 ArmAstBase.__init__(self, ArmAstBase.ksTypeBool); 273 283 assert fValue is True or fValue is False, '%s' % (fValue,); 274 284 self.fValue = fValue; … … 280 290 class ArmAstInteger(ArmAstBase): 281 291 def __init__(self, iValue): 282 ArmAstBase.__init__(self, ArmAstBase.k TypeInteger);292 ArmAstBase.__init__(self, ArmAstBase.ksTypeInteger); 283 293 self.iValue = int(iValue); 284 294 … … 286 296 return '%#x' % (self.iValue,); 287 297 298 288 299 class ArmAstSet(ArmAstBase): 289 300 def __init__(self, aoValues): 290 ArmAstBase.__init__(self, ArmAstBase.k TypeSet);301 ArmAstBase.__init__(self, ArmAstBase.ksTypeSet); 291 302 self.aoValues = aoValues; 292 303 … … 294 305 return '(%s)' % (', '.join([oValue.toString() for oValue in self.aoValues]),); 295 306 307 296 308 class ArmAstValue(ArmAstBase): 297 309 def __init__(self, sValue): 298 ArmAstBase.__init__(self, ArmAstBase.k TypeValue);310 ArmAstBase.__init__(self, ArmAstBase.ksTypeValue); 299 311 self.sValue = sValue; 300 312 … … 360 372 @staticmethod 361 373 def fromJson(oJson): 362 """ """363 374 assert oJson['_type'] in ('Instruction.Encodeset.Field', 'Instruction.Encodeset.Bits'), oJson['_type']; 364 375 … … 373 384 @staticmethod 374 385 def fromJsonEncodeset(oJson, aoSet, fCovered): 375 """ """376 386 assert oJson['_type'] == 'Instruction.Encodeset.Encodeset', oJson['_type']; 377 387 for oJsonValue in oJson['values']: … … 452 462 453 463 oCondition = ArmAstBase.fromJson(oJson['condition']); 454 print('debug transfer in: %s' % (oCondition.toString())); 464 #sCondBefore = oCondition.toString(); 465 #print('debug transfer: %s: org: %s' % (sInstrNm, sCondBefore)); 455 466 (oCondition, fMod) = transferConditionsToEncoding(oCondition, aoEncodesets, collections.defaultdict(list), sInstrNm); 456 if fMod: 457 print('debug transfer out: %s' % (oCondition.toString())); 467 #if fMod: 468 # print('debug transfer: %s: %s ----> %s' % (sInstrNm, sCondBefore, oCondition.toString())); 469 _ = fMod; 458 470 459 471 oInstr = ArmInstruction(oJson, sInstrNm, sInstrNm, aoEncodesets, oCondition); … … 478 490 The checks can be morphed into the 'size' field encoding criteria as '0b0x'. 479 491 """ 480 def isBoolTrue(oNode):481 return isinstance(oNode, ArmAstBool) and oNode.fValue is True;482 483 492 if isinstance(oCondition, ArmAstBinaryOp): 484 493 if oCondition.sOp == '&&': 485 print('debug transfer: %s: recursion...' % (sInstrNm,));486 494 # Recurse into each side of an AND expression. 495 #print('debug transfer: %s: recursion...' % (sInstrNm,)); 487 496 (oCondition.oLeft, fMod) = transferConditionsToEncoding(oCondition.oLeft, aoEncodesets, dPendingNotEq, 488 497 sInstrNm, uDepth + 1, fMod); 489 498 (oCondition.oRight, fMod) = transferConditionsToEncoding(oCondition.oRight, aoEncodesets, dPendingNotEq, 490 499 sInstrNm, uDepth + 1, fMod); 491 if isBoolTrue(oCondition.oLeft):500 if oCondition.oLeft.isBoolAndTrue(): 492 501 return (oCondition.oRight, fMod); 493 if isBoolTrue(oCondition.oRight):502 if oCondition.oRight.isBoolAndTrue(): 494 503 return (oCondition.oLeft, fMod); 495 504 496 505 elif oCondition.sOp in ('==', '!='): 497 506 # The pattern we're looking for is identifier (field) == fixed value. 498 print('debug transfer: %s: binaryop %s vs %s ...' % (sInstrNm, oCondition.oLeft.sType, oCondition.oRight.sType));507 #print('debug transfer: %s: binaryop %s vs %s ...' % (sInstrNm, oCondition.oLeft.sType, oCondition.oRight.sType)); 499 508 if ( isinstance(oCondition.oLeft, ArmAstIdentifier) 500 509 and isinstance(oCondition.oRight, (ArmAstValue, ArmAstInteger))): 501 510 sFieldName = oCondition.oLeft.sName; 502 511 oValue = oCondition.oRight; 503 print('debug transfer: %s: binaryop step 2...' % (sInstrNm,));512 #print('debug transfer: %s: binaryop step 2...' % (sInstrNm,)); 504 513 for oField in aoEncodesets: # ArmEncodesetField 505 514 if oField.sName and oField.sName == sFieldName: … … 512 521 assert oField.fValue == 0; 513 522 if oValue.iValue.bit_length() > oField.cBitsWidth: 514 raise Exception('%s: Condition field value check too wide: %s is %u bits, test value is%s (%u bits)'523 raise Exception('%s: Condition field value check too wide: %s is %u bits, test value %s (%u bits)' 515 524 % (sInstrNm, oField.sName, oField.cBitsWidth, oValue.iValue, 516 525 oValue.iValue.bit_count(),)); … … 523 532 break; 524 533 525 print('debug transfer: %s: integer binaryop -> encoding!' % (sInstrNm,)); 534 #print('debug transfer: %s: integer binaryop -> encoding: %s %s %#x/%#x' 535 # % (sInstrNm, oField.sName, oCondition.sOp, oValue.iValue, fFixed)); 526 536 if oCondition.sOp == '==': 527 537 oField.fValue = oValue.iValue; … … 542 552 % (sInstrNm, oField.sName, oField.fValue, oField.fFixed, oCondition.sOp, 543 553 oValue.sValue, fValue, fFixed)); 544 print('debug transfer: %s: value binaryop -> encoding!%s %s %#x (fFixed=%#x)'545 % (sInstrNm, oField.sName, oCondition.sOp, fValue, fFixed,));554 #print('debug transfer: %s: value binaryop -> encoding: %s %s %#x (fFixed=%#x)' 555 # % (sInstrNm, oField.sName, oCondition.sOp, fValue, fFixed,)); 546 556 if oCondition.sOp == '==': 547 557 oField.fValue |= fValue; … … 556 566 # 557 567 if uDepth == 0 and dPendingNotEq: 568 def recursiveRemove(oCondition, aoToRemove): 569 if isinstance(oCondition, ArmAstBinaryOp): 570 if oCondition.sOp == '&&': 571 oCondition.oLeft = recursiveRemove(oCondition.oLeft, aoToRemove); 572 oCondition.oRight = recursiveRemove(oCondition.oLeft, aoToRemove); 573 if oCondition.oLeft.isBoolAndTrue(): return oCondition.oRight; 574 if oCondition.oRight.isBoolAndTrue(): return oCondition.oLeft; 575 elif oCondition in aoToRemove: 576 assert isinstance(oCondition.oLeft, ArmAstIdentifier); 577 assert isinstance(oCondition.oRight, (ArmAstValue, ArmAstInteger)); 578 assert oCondition.sOp == '!='; 579 return ArmAstBool(True); 580 return oCondition; 581 558 582 for sFieldNm, atOccurences in dPendingNotEq.items(): 559 583 # For a two bit field, we need at least two occurences to get any kind of fixed value. … … 573 597 fFixed = 3; # Both bits are fixed. 574 598 fValue = afValues[0] & fFixed; 575 print('debug transfer: %s: %u binaryops -> encoding! %s != %#x/%#x' 576 % (sInstrNm, len(atOccurences), oField.sName, fValue, fFixed,)); 599 print('debug transfer: %s: %u binaryops -> encoding: %s == %#x/%#x' 600 % (sInstrNm, len(atOccurences), sFieldNm, ~fValue & fFixed, fFixed,)); 601 oField.fValue |= ~fValue & fFixed; 602 oField.fFixed |= fFixed; 603 577 604 578 605 # Remove the associated conditions (they'll be leaves). 579 aoToRemove = [oCondition for _, _, _, oCondition in atOccurences]; 580 def recursiveRemove(oCondition): 581 if isinstance(oCondition, ArmAstBinaryOp): 582 if oCondition.sOp == '&&': 583 oCondition.oLeft = recursiveRemove(oCondition.oLeft); 584 oCondition.oRight = recursiveRemove(oCondition.oLeft); 585 if isBoolTrue(oCondition.oLeft): return oCondition.oRight; 586 if isBoolTrue(oCondition.oRight): return oCondition.oLeft; 587 elif oCondition in aoToRemove: 588 assert isinstance(oCondition.oLeft, ArmAstIdentifier); 589 assert isinstance(oCondition.oRight, (ArmAstValue, ArmAstInteger)); 590 assert oCondition.sOp == '!='; 591 return ArmAstBool(True); 592 return oCondition; 593 oCondition = recursiveRemove(oCondition); 606 oCondition = recursiveRemove(oCondition, [oCondition for _, _, _, oCondition in atOccurences]); 594 607 fMod = True; 595 608 else: 596 609 print('info: %s: transfer cond to enc failed for: %s dValues=%s dFixed=%s' 597 % (sInstrNm, oField.sName, dValues, dFixed));610 % (sInstrNm, sFieldNm, dValues, dFixed)); 598 611 elif oField.cBitsWidth == 3 and len(atOccurences) >= 7: 599 print('info: %s: TODO: transfer cond to enc for 3 bit field: %s (%s)' % (sInstrNm, oField.sName, atOccurences,));612 print('info: %s: TODO: transfer cond to enc for 3 bit field: %s (%s)' % (sInstrNm, sFieldNm, atOccurences,)); 600 613 601 614 return (oCondition, fMod); … … 729 742 #print("oBrk=%s" % (oBrk,)) 730 743 731 if True:744 if oOptions.fPrintInstructions: 732 745 for oInstr in g_aoAllArmInstructions: 733 746 print('%08x/%08x %s %s' % (oInstr.fFixedMask, oInstr.fFixedValue, oInstr.getCName(), oInstr.sAsmDisplay)); 734 747 735 748 # Gather stats on fixed bits: 736 if True:749 if oOptions.fPrintFixedMaskStats: 737 750 dCounts = collections.Counter(); 738 751 for oInstr in g_aoAllArmInstructions: … … 747 760 748 761 # Top 10 fixed masks. 749 if True:762 if oOptions.fPrintFixedMaskTop10: 750 763 dCounts = collections.Counter(); 751 764 for oInstr in g_aoAllArmInstructions: … … 764 777 # 765 778 766 class MaskIterator (object):779 class MaskIterator1(object): 767 780 """ Helper class for DecoderNode.constructNextLevel(). """ 768 781 … … 790 803 elif len(dBits) > 0: 791 804 aaiMaskAlgo = DecoderNode.compactMaskAsList(list(dBits)); 792 if len(aaiMaskAlgo) <= MaskIterator .kcMaxMaskParts:805 if len(aaiMaskAlgo) <= MaskIterator1.kcMaxMaskParts: 793 806 dDictDoneAlready[fMask] = 1; 794 807 aiRet = [(fMask, list(dBits), aaiMaskAlgo)]; … … 802 815 if len(dBits) <= cMaxTableSizeInBits: 803 816 aaiMaskAlgo = DecoderNode.compactMaskAsList(list(dBits)); 804 if len(aaiMaskAlgo) <= MaskIterator .kcMaxMaskParts:817 if len(aaiMaskAlgo) <= MaskIterator1.kcMaxMaskParts: 805 818 dDictDoneAlready[fMask] = 1; 806 819 aiRet.append((fMask, list(dBits), aaiMaskAlgo)); … … 817 830 recursive(fMask & ~(1 << iBit), dChildBits) 818 831 819 print("debug: fMask=%#x len(aiRet)=%d " % (fMask, len(aiRet),));832 print("debug: fMask=%#x len(aiRet)=%d dDictDoneAlready=%d" % (fMask, len(aiRet), len(dDictDoneAlready))); 820 833 return aiRet; 834 835 class MaskIterator2(object): 836 """ Helper class for DecoderNode.constructNextLevel(). """ 837 838 ## Maximum number of mask sub-parts. 839 # Lower number means fewer instructions required to convert it into an index. 840 kcMaxMaskParts = 3 841 842 class StackEntry(object): 843 def __init__(self, fMask, aiBits): 844 self.fMask = fMask; 845 self.aiBits = aiBits; 846 self.iCur = -1; 847 #fTmp = 0; 848 #for iBit in aiBits: 849 # fTmp |= 1 << iBit; 850 #assert fTmp == fMask, 'fTmp=%#x fMask=%#x aiBits=%s' % (fTmp, fMask, aiBits); 851 852 def __init__(self, fMask, cMaxTableSizeInBits, dDictDoneAlready): 853 self.fMask = fMask; 854 self.cMaxTableSizeInBits = cMaxTableSizeInBits; 855 self.dDictDoneAlready = dDictDoneAlready; 856 self.cReturned = 0; 857 self.cLoops = 0; 858 859 dBits = collections.OrderedDict(); 860 for iBit in range(32): 861 if fMask & (1 << iBit): 862 dBits[iBit] = 1; 863 self.oTop = self.StackEntry(fMask, list(dBits)); 864 self.aoStack = []; 865 866 def __iter__(self): 867 return self; 868 869 def __next__(self): 870 oTop = self.oTop; 871 while oTop: 872 self.cLoops += 1 873 iCur = oTop.iCur; 874 cCurBits = len(oTop.aiBits); 875 if iCur < 0: 876 # Return self if appropriate 877 if ( 0 < cCurBits < self.cMaxTableSizeInBits 878 and oTop.fMask not in self.dDictDoneAlready): 879 aaiMaskAlgo = []#DecoderNode.compactMaskAsList(oTop.aiBits); 880 if len(aaiMaskAlgo) <= MaskIterator2.kcMaxMaskParts: 881 oTop.iCur = 0; 882 self.dDictDoneAlready[oTop.fMask] = 1; 883 self.cReturned += 1; 884 #return (oTop.fMask, oTop.aiBits, aaiMaskAlgo); 885 iCur = 0; 886 887 if iCur < cCurBits and cCurBits > 1: 888 # push 889 oTop.iCur = iCur + 1; 890 self.aoStack.append(oTop); 891 oTop = self.StackEntry(oTop.fMask & ~(1 << oTop.aiBits[iCur]), oTop.aiBits[:iCur] + oTop.aiBits[iCur + 1:]); 892 self.oTop = oTop; 893 else: 894 # pop. 895 oTop.iCur = 0xff; 896 oTop = self.aoStack.pop() if self.aoStack else None; 897 self.oTop = oTop; 898 # Done; 899 print('MaskIterator2: fMask=%#x -> %u items returned; %u loops' % (self.fMask, self.cReturned, self.cLoops)); 900 raise StopIteration; 901 902 class MaskIterator(object): 903 """ Helper class for DecoderNode.constructNextLevel(). """ 904 905 ## Maximum number of mask sub-parts. 906 # Lower number means fewer instructions required to convert it into an index. 907 # This is implied by the code in compileMaskCompactorLimited. 908 kcMaxMaskParts = 3 909 910 def __init__(self, fMask, cMaxTableSizeInBits, dDictDoneAlready): 911 self.fMask = fMask; 912 self.aaiAlgo = MaskIterator.compileMaskCompactor(fMask); 913 self.fCompactMask = DecoderNode.toIndexByMask(fMask, self.aaiAlgo); 914 #print('debug: fMask=%#x -> fCompactMask=%#x aaiAlgo=%s' % (fMask, self.fCompactMask, self.aaiAlgo)); 915 self.fnExpandMask = DecoderNode.compactDictAlgoToLambdaRev(self.aaiAlgo); 916 self.cMaxTableSizeInBits = cMaxTableSizeInBits; 917 self.dDictDoneAlready = dDictDoneAlready; 918 self.cReturned = 0; 919 920 @staticmethod 921 def compileMaskCompactor(fMask): 922 """ 923 Returns an with instructions for extracting the bits from the mask into 924 a compacted form. Each array entry is an array/tuple of source bit [0], 925 destination bit [1], and bit counts [2]. 926 """ 927 aaiAlgo = []; 928 iSrcBit = 0; 929 iDstBit = 0; 930 while fMask > 0: 931 # Skip leading zeros. 932 cSkip = (fMask & -fMask).bit_length() - 1; 933 #assert (fMask & ((1 << cSkip) - 1)) == 0 and ((fMask >> cSkip) & 1), 'fMask=%#x cSkip=%d' % (fMask, cSkip) 934 iSrcBit += cSkip; 935 fMask >>= cSkip; 936 937 # Calculate leading ones the same way. 938 cCount = (~fMask & -~fMask).bit_length() - 1; 939 #assert (fMask & ((1 << cCount) - 1)) == ((1 << cCount) - 1) and (fMask & (1 << cCount)) == 0 940 941 # Append to algo list. 942 aaiAlgo.append((iSrcBit, iDstBit, (1 << cCount) - 1)); 943 944 # Advance. 945 iDstBit += cCount; 946 iSrcBit += cCount; 947 fMask >>= cCount; 948 return aaiAlgo; 949 950 @staticmethod 951 def compileMaskCompactorLimited(fMask): 952 """ 953 Version of compileMaskCompactor that returns an empty list if there are 954 more than three sections. 955 """ 956 assert fMask; 957 958 # 959 # Chunk 0: 960 # 961 962 # Skip leading zeros. 963 iSrcBit0 = (fMask & -fMask).bit_length() - 1; 964 fMask >>= iSrcBit0; 965 # Calculate leading ones the same way. 966 cCount0 = (~fMask & -~fMask).bit_length() - 1; 967 fMask >>= cCount0; 968 if not fMask: 969 return [(iSrcBit0, 0, (1 << cCount0) - 1)]; 970 971 # 972 # Chunk 1: 973 # 974 975 # Skip leading zeros. 976 cSrcGap1 = (fMask & -fMask).bit_length() - 1; 977 fMask >>= cSrcGap1; 978 # Calculate leading ones the same way. 979 cCount1 = (~fMask & -~fMask).bit_length() - 1; 980 fMask >>= cCount1; 981 if not fMask: 982 return [ (iSrcBit0, 0, (1 << cCount0) - 1), 983 (iSrcBit0 + cCount0 + cSrcGap1, cCount0, (1 << cCount1) - 1)]; 984 985 # 986 # Chunk 2: 987 # 988 989 # Skip leading zeros. 990 cSrcGap2 = (fMask & -fMask).bit_length() - 1; 991 fMask >>= cSrcGap2; 992 # Calculate leading ones the same way. 993 cCount2 = (~fMask & -~fMask).bit_length() - 1; 994 fMask >>= cCount2; 995 if not fMask: 996 iSrcBit1 = iSrcBit0 + cCount0 + cSrcGap1; 997 return [ (iSrcBit0, 0, (1 << cCount0) - 1), 998 (iSrcBit1, cCount0, (1 << cCount1) - 1), 999 (iSrcBit1 + cCount1 + cSrcGap2, cCount0 + cCount1, (1 << cCount2) - 1), ]; 1000 1001 # Too many fragments. 1002 return []; 1003 1004 @staticmethod 1005 def maskCompactorAlgoToBitList(aaiAlgo): 1006 aiRet = []; 1007 for iSrcBit, _, fMask in aaiAlgo: 1008 cCount = fMask.bit_count(); 1009 aiRet += [iSrcBit + i for i in range(cCount)]; 1010 return aiRet; 1011 1012 def __iter__(self): 1013 return self; 1014 1015 def __next__(self): 1016 fCompactMask = self.fCompactMask; 1017 while fCompactMask != 0: 1018 cCurBits = fCompactMask.bit_count(); 1019 if cCurBits <= self.cMaxTableSizeInBits: 1020 fMask = self.fnExpandMask(fCompactMask); 1021 if fMask not in self.dDictDoneAlready: 1022 aaiMaskAlgo = MaskIterator.compileMaskCompactorLimited(fMask); 1023 if aaiMaskAlgo: 1024 #assert aaiMaskAlgo == MaskIterator.compileMaskCompactor(fMask), \ 1025 # '%s vs %s' % (aaiMaskAlgo, MaskIterator.compileMaskCompactor(fMask)); 1026 self.dDictDoneAlready[fMask] = 1; 1027 self.fCompactMask = fCompactMask - 1; 1028 self.cReturned += 1; 1029 return (fMask, MaskIterator.maskCompactorAlgoToBitList(aaiMaskAlgo), aaiMaskAlgo); 1030 fCompactMask -= 1; 1031 self.fCompactMask = 0; 1032 #print('MaskIterator: fMask=%#x -> %u items returned' % (self.fMask, self.cReturned)); 1033 raise StopIteration; 1034 821 1035 822 1036 class DecoderNode(object): … … 841 1055 ); 842 1056 843 def __init__(self, aoInstructions : list[ArmInstruction], fCheckedMask: int, fCheckedValue: int, uDepth: int):1057 def __init__(self, aoInstructions, fCheckedMask, fCheckedValue, uDepth): 844 1058 assert (~fCheckedMask & fCheckedValue) == 0; 845 1059 for idxInstr, oInstr in enumerate(aoInstructions): 846 1060 assert ((oInstr.fFixedValue ^ fCheckedValue) & fCheckedMask & oInstr.fFixedMask) == 0, \ 847 '%s: fFixedValue=%#x fFixedMask=%#x fCheckedValue=%#x fCheckedMask=%#x -> %#x\n %s' \1061 '%s: fFixedValue=%#x fFixedMask=%#x fCheckedValue=%#x fCheckedMask=%#x -> %#x\naoInstructions: len=%s\n %s' \ 848 1062 % (idxInstr, oInstr.fFixedValue, oInstr.fFixedMask, fCheckedValue, fCheckedMask, 849 1063 (oInstr.fFixedValue ^ fCheckedValue) & fCheckedMask & oInstr.fFixedMask, 850 '\n '.join(['%s: %#010x/%#010x %s' % (i, oInstr2.fFixedValue, oInstr2.fFixedMask, oInstr2.sName) 851 for i, oInstr2 in enumerate(aoInstructions[:idxInstr+2])])); 1064 len(aoInstructions), 1065 '\n '.join(['%s%s: %#010x/%#010x %s' % ('*' if i == idxInstr else ' ', i, 1066 oInstr2.fFixedValue, oInstr2.fFixedMask, oInstr2.sName) 1067 for i, oInstr2 in enumerate(aoInstructions[:idxInstr+8])])); 852 1068 853 1069 self.aoInstructions = aoInstructions; ##< The instructions at this level. … … 871 1087 iDstBit = 0; 872 1088 while fMask > 0: 873 if fMask & 1: 874 cCount = 1 1089 # Skip leading zeros. 1090 cSkip = (fMask & -fMask).bit_length() - 1; 1091 assert (fMask & ((1 << cSkip) - 1)) == 0 and ((fMask >> cSkip) & 1), 'fMask=%#x cSkip=%d' % (fMask, cSkip) 1092 iSrcBit += cSkip; 1093 fMask >>= cSkip; 1094 1095 # Calculate leading ones the same way. 1096 cCount1 = (~fMask & -~fMask).bit_length() - 1; 1097 cCount = 1 1098 fMask >>= 1; 1099 while fMask & 1: 875 1100 fMask >>= 1; 876 while fMask & 1: 877 fMask >>= 1; 878 cCount += 1 879 aaiAlgo.append([iSrcBit, iDstBit, cCount]) 880 iSrcBit += cCount; 881 iDstBit += cCount; 882 else: 883 iSrcBit += 1; 1101 cCount += 1 1102 assert cCount1 == cCount; 1103 aaiAlgo.append([iSrcBit, iDstBit, (1 << cCount) - 1]) 1104 iSrcBit += cCount; 1105 iDstBit += cCount; 884 1106 return aaiAlgo; 885 1107 886 1108 @staticmethod 887 def compactMaskAsList( dOrderedDict):1109 def compactMaskAsList(aiOrderedBits): 888 1110 """ 889 1111 Returns an with instructions for extracting the bits from the mask into … … 894 1116 iDstBit = 0; 895 1117 i = 0; 896 while i < len( dOrderedDict):897 iSrcBit = dOrderedDict[i];1118 while i < len(aiOrderedBits): 1119 iSrcBit = aiOrderedBits[i]; 898 1120 cCount = 1; 899 1121 i += 1; 900 while i < len( dOrderedDict) and dOrderedDict[i] == iSrcBit + cCount:1122 while i < len(aiOrderedBits) and aiOrderedBits[i] == iSrcBit + cCount: 901 1123 cCount += 1; 902 1124 i += 1; … … 907 1129 @staticmethod 908 1130 def compactDictAlgoToLambda(aaiAlgo): 909 assert (aaiAlgo)1131 assert aaiAlgo; 910 1132 sBody = ''; 911 1133 for iSrcBit, iDstBit, fMask in aaiAlgo: … … 924 1146 @staticmethod 925 1147 def compactDictAlgoToLambdaRev(aaiAlgo): 926 assert (aaiAlgo)1148 assert aaiAlgo; 927 1149 sBody = ''; 928 1150 for iSrcBit, iDstBit, fMask in aaiAlgo: … … 957 1179 Recursively constructs the 958 1180 """ 1181 # 959 1182 # Special case: leaf. 1183 # 960 1184 if len(self.aoInstructions) <= 1: 961 1185 assert len(self.aoChildren) == 0; 962 1186 return 16 if self.fLeafCheckNeeded else 0; 963 1187 sDbgPrefix = 'debug/%u: %s' % (self.uDepth, ' ' * self.uDepth); 1188 1189 # 964 1190 # Do an inventory of the fixed masks used by the instructions. 1191 # 965 1192 dMaskCounts = collections.Counter(); 966 1193 for oInstr in self.aoInstructions: … … 969 1196 'dMaskCounts=%s len(self.aoInstructions)=%s\n%s' % (dMaskCounts, len(self.aoInstructions),self.aoInstructions); 970 1197 971 # Determine the max table size for the number of instructions we have.972 cInstructionsAsShift = 1;973 while (1 << cInstructionsAsShift) < len(self.aoInstructions):974 cInstructionsAsShift += 1;1198 ## Determine the max table size for the number of instructions we have. 1199 #cInstructionsAsShift = 1; 1200 #while (1 << cInstructionsAsShift) < len(self.aoInstructions): 1201 # cInstructionsAsShift += 1; 975 1202 #cMaxTableSizeInBits = self.kacMaxTableSizesInBits[cInstructionsAsShift]; 976 1203 977 # Work thru the possible masks and test out the possible variations (brute force style). 1204 # 1205 # Work thru the possible masks and test out the variations (brute force style). 1206 # 978 1207 uCostBest = 0x7fffffffffffffff; 979 1208 fChildrenBest = 0; 980 aoChildrenBest = None; 981 dDictDoneAlready = {} 1209 aoChildrenBest = []; 1210 1211 dDictDoneAlready = {}; 982 1212 for fOrgMask, cOccurences in dMaskCounts.most_common(8): 983 1213 cOccurencesAsShift = 1; … … 985 1215 cOccurencesAsShift += 1; 986 1216 cMaxTableSizeInBits = self.kacMaxTableSizesInBits[cOccurencesAsShift]; # Not quite sure about this... 987 print('debug: %#010x (%u) - %u instructions - max tab size %u' 988 % (fOrgMask, self.popCount(fOrgMask), cOccurences, cMaxTableSizeInBits,)); 1217 if self.uDepth <= 1: 1218 print('%s===== Start: %#010x (%u) - %u instructions - max tab size %u =====' 1219 % (sDbgPrefix, fOrgMask, self.popCount(fOrgMask), cOccurences, cMaxTableSizeInBits,)); 989 1220 990 1221 # Skip pointless stuff. 991 1222 if cOccurences >= 2 and fOrgMask > 0 and fOrgMask != 0xffffffff: 992 993 # Brute force all the mask variations (minus those which are too wide). 1223 # 1224 # Brute force relevant mask variations. 1225 # (The MaskIterator skips masks that are too wide and too fragmented.) 1226 # 994 1227 for fMask, dOrderedDictMask, aaiMaskToIdxAlgo in MaskIterator(fOrgMask, cMaxTableSizeInBits, dDictDoneAlready): 995 print('debug: >>> fMask=%#010x...' % (fMask,)); 1228 #print('%s>>> fMask=%#010x dOrderedDictMask=%s aaiMaskToIdxAlgo=%s)...' 1229 # % (sDbgPrefix, fMask, dOrderedDictMask, aaiMaskToIdxAlgo)); 996 1230 assert len(dOrderedDictMask) <= cMaxTableSizeInBits; 1231 1232 # Compile the indexing/unindexing functions. 997 1233 fnToIndex = self.compactDictAlgoToLambda(aaiMaskToIdxAlgo); 998 1234 fnFromIndex = self.compactDictAlgoToLambdaRev(aaiMaskToIdxAlgo); 999 1235 1236 # Create an temporary table empty with empty lists as entries. 1237 ## @todo is there a better way for doing this? collections.defaultdict? 1000 1238 aaoTmp = []; 1001 for i in range(1 << len(dOrderedDictMask)): 1002 aaoTmp.append(list()); 1003 1239 for _ in range(1 << len(dOrderedDictMask)): 1240 aaoTmp.append([]); 1241 1242 # Insert the instructions into the temporary table. 1004 1243 for oInstr in self.aoInstructions: 1005 1244 idx = fnToIndex(oInstr.fFixedValue); 1006 # idx = self.toIndexByMask(oInstr.fFixedValue, aaiMaskToIdxAlgo)1007 assert idx == self.toIndexByMask(oInstr.fFixedValue & fMask, aaiMaskToIdxAlgo);1008 print('debug: %#010x -> %#05x %s' % (oInstr.fFixedValue, idx, oInstr.sName));1245 #assert idx == self.toIndexByMask(oInstr.fFixedValue & fMask, aaiMaskToIdxAlgo); 1246 #assert idx == fnToIndex(fnFromIndex(idx)); 1247 #print('%s%#010x -> %#05x %s' % (sDbgPrefix, oInstr.fFixedValue, idx, oInstr.sName)); 1009 1248 aoList = aaoTmp[idx]; 1010 1249 aoList.append(oInstr); 1011 1250 1251 # Construct decoder nodes from the aaoTmp lists, construct sub-levels and calculate costs. 1252 uCostTmp = 0; ## @todo calc base cost from table size and depth. 1012 1253 aoChildrenTmp = []; 1013 uCostTmp = 0;1014 1254 for idx, aoInstrs in enumerate(aaoTmp): 1015 1255 oChild = DecoderNode(aoInstrs, … … 1020 1260 uCostTmp += oChild.constructNextLevel(); 1021 1261 1262 # Is this mask better than the previous? 1022 1263 if uCostTmp < uCostBest: 1264 if self.uDepth <= 1: 1265 print('%s~~~ New best! fMask=%#010x uCost=%#x (previous %#010x / %#x) ...' 1266 % (sDbgPrefix, fMask, uCostTmp, fChildrenBest, uCostBest, )); 1023 1267 uCostBest = uCostTmp; 1024 1268 fChildrenBest = fMask; 1025 1269 aoChildrenBest = aoChildrenTmp; 1026 1270 1271 if self.uDepth <= 1: 1272 print('%s===== Final: fMask=%#010x uCost=%#x TabSize=%#x Instructions=%u...' 1273 % (sDbgPrefix, fChildrenBest, uCostBest, len(aoChildrenBest), len(self.aoInstructions))); 1027 1274 if aoChildrenBest is None: 1028 1275 pass; ## @todo 1276 1277 # Done. 1278 self.fChildMask = fChildrenBest; 1279 self.aoChildren = aoChildrenBest; 1280 self.uCost = uCostBest; 1281 1029 1282 return uCostBest; 1030 1031 1032 1033 1034 1035 1036 1037 1283 1038 1284 … … 1051 1297 Creates the decoder to the best our abilities. 1052 1298 """ 1053 global g_aoAllArmInstructions;1054 1299 self.oDecoderRoot = DecoderNode(g_aoAllArmInstructions, 0, 0, 0); 1055 1300 self.oDecoderRoot.constructNextLevel(); … … 1175 1420 """ Main function. """ 1176 1421 1422 #for _ in MaskIterator(0xffc0ff00, 12, {}): 1423 # pass; 1424 #return 2; 1425 1177 1426 # 1178 1427 # Parse arguments. … … 1215 1464 default = '-', 1216 1465 help = 'The output C++ file for the decoder.'); 1466 # debug: 1467 oArgParser.add_argument('--print-instructions', 1468 dest = 'fPrintInstructions', 1469 action = 'store_true', 1470 default = False, 1471 help = 'List the instructions after loading.'); 1472 oArgParser.add_argument('--print-fixed-mask-stats', 1473 dest = 'fPrintFixedMaskStats', 1474 action = 'store_true', 1475 default = False, 1476 help = 'List statistics on fixed bit masks.'); 1477 oArgParser.add_argument('--print-fixed-mask-top-10', 1478 dest = 'fPrintFixedMaskTop10', 1479 action = 'store_true', 1480 default = False, 1481 help = 'List the 10 top fixed bit masks.'); 1482 # Do it! 1217 1483 oOptions = oArgParser.parse_args(asArgs[1:]); 1218 1484 … … 1254 1520 return 1; 1255 1521 1522 def printException(oXcpt): 1523 print('----- Exception Caught! -----', flush = True); 1524 cMaxLines = 1; 1525 try: cchMaxLen = os.get_terminal_size()[0] * cMaxLines; 1526 except: cchMaxLen = 80 * cMaxLines; 1527 cchMaxLen -= len(' = ...'); 1528 1529 oTB = traceback.TracebackException.from_exception(oXcpt, limit = None, capture_locals = True); 1530 # No locals for the outer frame. 1531 oTB.stack[0].locals = {}; 1532 # Suppress insanely long variable values. 1533 for oFrameSummary in oTB.stack: 1534 if oFrameSummary.locals: 1535 #for sToDelete in ['ddAsmRules', 'aoInstructions',]: 1536 # if sToDelete in oFrameSummary.locals: 1537 # del oFrameSummary.locals[sToDelete]; 1538 for sKey, sValue in oFrameSummary.locals.items(): 1539 if len(sValue) > cchMaxLen - len(sKey): 1540 sValue = sValue[:cchMaxLen - len(sKey)] + ' ...'; 1541 if '\n' in sValue: 1542 sValue = sValue.split('\n')[0] + ' ...'; 1543 oFrameSummary.locals[sKey] = sValue; 1544 idxFrame = 0; 1545 asFormatted = []; 1546 oReFirstFrameLine = re.compile(r'^ File ".*", line \d+, in ') 1547 for sLine in oTB.format(): 1548 if oReFirstFrameLine.match(sLine): 1549 idxFrame += 1; 1550 asFormatted.append(sLine); 1551 for sLine in asFormatted: 1552 if oReFirstFrameLine.match(sLine): 1553 idxFrame -= 1; 1554 sLine = '#%u %s' % (idxFrame, sLine.lstrip()); 1555 print(sLine); 1556 print('----', flush = True); 1256 1557 1257 1558 if __name__ == '__main__': 1559 #for fOrgMask in (1, 3, 7, 15, 31): 1560 # print('Test %#x:' % (fOrgMask,)); 1561 # for x in MaskIterator(fOrgMask, 16, {}): 1562 # print('MaskIterator: fMask=%#04x aiBits=%20s aaiAlgo=%s' % (x[0],x[1],x[2])); 1563 fProfileIt = True; 1564 oProfiler = cProfile.Profile() if fProfileIt else None; 1258 1565 try: 1259 sys.exit(IEMArmGenerator().main(sys.argv)); 1260 except Exception as oXcpt: 1261 print('Exception Caught!', flush = True); 1262 cMaxLines = 1; 1263 try: cchMaxLen = os.get_terminal_size()[0] * cMaxLines; 1264 except: cchMaxLen = 80 * cMaxLines; 1265 cchMaxLen -= len(' = ...'); 1266 1267 oTB = traceback.TracebackException.from_exception(oXcpt, limit = None, capture_locals = True); 1268 # No locals for the outer frame. 1269 oTB.stack[0].locals = {}; 1270 # Suppress insanely long variable values. 1271 for oFrameSummary in oTB.stack: 1272 if oFrameSummary.locals: 1273 #for sToDelete in ['ddAsmRules', 'aoInstructions',]: 1274 # if sToDelete in oFrameSummary.locals: 1275 # del oFrameSummary.locals[sToDelete]; 1276 for sKey, sValue in oFrameSummary.locals.items(): 1277 if len(sValue) > cchMaxLen - len(sKey): 1278 sValue = sValue[:cchMaxLen - len(sKey)] + ' ...'; 1279 if '\n' in sValue: 1280 sValue = sValue.split('\n')[0] + ' ...'; 1281 oFrameSummary.locals[sKey] = sValue; 1282 oTB.print(); 1283 1566 if not oProfiler: 1567 rcExit = IEMArmGenerator().main(sys.argv); 1568 else: 1569 rcExit = oProfiler.runcall(IEMArmGenerator().main, sys.argv); 1570 except Exception as oXcptOuter: 1571 printException(oXcptOuter); 1572 rcExit = 2; 1573 except KeyboardInterrupt as oXcptOuter: 1574 printException(oXcptOuter); 1575 rcExit = 2; 1576 if oProfiler: 1577 oProfiler.print_stats(sort='tottime'); 1578 sys.exit(rcExit); 1579 1580
Note:
See TracChangeset
for help on using the changeset viewer.