Changeset 108916 in vbox for trunk/src/VBox/VMM/VMMAll
- Timestamp:
- Apr 9, 2025 11:32:33 AM (4 weeks ago)
- svn:sync-xref-src-repo-rev:
- 168397
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/target-armv8/bsd-spec-analyze.py
r108904 r108916 836 836 s_oReValidName = re.compile('^[_A-Za-z][_A-Za-z0-9]+$'); 837 837 838 def __init__(self, oJson, sName, sMemonic, aoEncodesets, oCondition):838 def __init__(self, oJson, sName, sMemonic, sAsmDisplay, aoEncodesets, oCondition): 839 839 assert self.s_oReValidName.match(sName), 'sName=%s' % (sName); 840 840 self.oJson = oJson; 841 841 self.sName = sName; 842 842 self.sMnemonic = sMemonic; 843 self.sAsmDisplay = ''; 843 self.sAsmDisplay = sAsmDisplay; 844 self.sSet = None; 845 self.asGroups = []; 844 846 self.aoEncodesets = aoEncodesets; 845 847 self.oCondition = oCondition; … … 889 891 # 890 892 893 ## The '_meta::version' dictionary from the Instructions.json file. 894 g_oArmInstructionVerInfo = None; 895 891 896 ## All the instructions. 892 897 g_aoAllArmInstructions = [] # type: List[ArmInstruction] 893 898 894 ## All the instructions by name (not mnemonic .899 ## All the instructions by name (not mnemonic). 895 900 g_dAllArmInstructionsByName = {} # type: Dict[ArmInstruction] 896 901 897 # 898 # Pass #1 - Snoop up all the instructions and their encodings. 899 # 900 def parseInstructions(aoStack, aoJson): 902 ## All the instruction by instruction set name. 903 g_dAllArmInstructionsBySet = {} # type: Dict[List[ArmInstruction]] 904 905 ## All the instruction by instruction group name. 906 g_dAllArmInstructionsByGroup = {} # type: Dict[List[ArmInstruction]] 907 908 909 def __asmChoicesFilterOutDefaultAndAbsent(adChoices, ddAsmRules): 910 """ 911 Helper that __asmRuleIdToDisplayText uses to filter out any default choice 912 that shouldn't be displayed. 913 914 Returns choice list. 915 """ 916 # There are sometime a 'none' tail entry. 917 if adChoices[-1] is None: 918 adChoices = adChoices[:-1]; 919 if len(adChoices) > 1: 920 # Typically, one of the choices is 'absent' or 'default', eliminate it before we start... 921 for iChoice, dChoice in enumerate(adChoices): 922 fAllAbsentOrDefault = True; 923 for dSymbol in dChoice['symbols']: 924 if dSymbol['_type'] != 'Instruction.Symbols.RuleReference': 925 fAllAbsentOrDefault = False; 926 break; 927 sRuleId = dSymbol['rule_id']; 928 oRule = ddAsmRules[sRuleId]; 929 if ( ('display' in oRule and oRule['display']) 930 or ('symbols' in oRule and oRule['symbols'])): 931 fAllAbsentOrDefault = False; 932 break; 933 if fAllAbsentOrDefault: 934 return adChoices[:iChoice] + adChoices[iChoice + 1:]; 935 return adChoices; 936 937 938 def __asmRuleIdToDisplayText(sRuleId, ddAsmRules, sInstrNm): 939 """ 940 Helper that asmSymbolsToDisplayText uses to process assembly rule references. 941 """ 942 dRule = ddAsmRules[sRuleId]; 943 sRuleType = dRule['_type']; 944 if sRuleType == 'Instruction.Rules.Token': 945 assert dRule['default'], '%s: %s' % (sInstrNm, sRuleId); 946 return dRule['default']; 947 if sRuleType == 'Instruction.Rules.Rule': 948 assert dRule['display'], '%s: %s' % (sInstrNm, sRuleId); 949 return dRule['display']; 950 if sRuleType == 'Instruction.Rules.Choice': 951 # Some of these has display = None and we need to sort it out ourselves. 952 if dRule['display']: 953 return dRule['display']; 954 sText = '{'; 955 assert len(dRule['choices']) > 1; 956 for iChoice, dChoice in enumerate(__asmChoicesFilterOutDefaultAndAbsent(dRule['choices'], ddAsmRules)): 957 if iChoice > 0: 958 sText += ' | '; 959 sText += asmSymbolsToDisplayText(dChoice['symbols'], ddAsmRules, sInstrNm); 960 sText += '}'; 961 962 # Cache it. 963 dRule['display'] = sText; 964 return sText; 965 966 raise Exception('%s: Unknown assembly rule type: %s for %s' % (sInstrNm, sRuleType, sRuleId)); 967 968 969 def asmSymbolsToDisplayText(adSymbols, ddAsmRules, sInstrNm): 970 """ 971 Translates the 'symbols' array of an instruction's 'assembly' property into 972 a kind of assembly syntax outline. 973 """ 974 sText = ''; 975 for dSym in adSymbols: 976 sType = dSym['_type']; 977 if sType == 'Instruction.Symbols.Literal': 978 sText += dSym['value']; 979 elif sType == 'Instruction.Symbols.RuleReference': 980 sRuleId = dSym['rule_id']; 981 sText += __asmRuleIdToDisplayText(sRuleId, ddAsmRules, sInstrNm); 982 else: 983 raise Exception('%s: Unknown assembly symbol type: %s' % (sInstrNm, sType,)); 984 return sText; 985 986 987 def parseInstructions(aoStack, aoJson, ddAsmRules): 901 988 for oJson in aoJson: 902 989 if oJson['_type'] == "Instruction.InstructionSet": 903 parseInstructions([oJson,] + aoStack, oJson['children']); 990 assert oJson['name']; 991 parseInstructions([oJson,] + aoStack, oJson['children'], ddAsmRules); 992 904 993 elif oJson['_type'] == "Instruction.InstructionGroup": 905 parseInstructions([oJson,] + aoStack, oJson['children']); 994 assert oJson['name']; 995 parseInstructions([oJson,] + aoStack, oJson['children'], ddAsmRules); 996 906 997 elif oJson['_type'] == "Instruction.Instruction": 998 # 999 # Start by getting the instruction attributes. 1000 # 907 1001 sInstrNm = oJson['name']; 908 1002 … … 920 1014 _ = fMod; 921 1015 922 oInstr = ArmInstruction(oJson, sInstrNm, sInstrNm, aoEncodesets, oCondition); 923 1016 # Come up with the assembly syntax (sAsmDisplay). 1017 if 'assembly' in oJson: 1018 oAsm = oJson['assembly']; 1019 assert oAsm['_type'] == 'Instruction.Assembly'; 1020 assert 'symbols' in oAsm; 1021 sAsmDisplay = asmSymbolsToDisplayText(oAsm['symbols'], ddAsmRules, sInstrNm); 1022 else: 1023 sAsmDisplay = sInstrNm; 1024 1025 # We derive the mnemonic from the assembly display string. 1026 sMnemonic = sAsmDisplay.split()[0]; 1027 1028 # 1029 # Instantiate it. 1030 # 1031 oInstr = ArmInstruction(oJson, sInstrNm, sMnemonic, sAsmDisplay, aoEncodesets, oCondition); 1032 1033 # 1034 # Add the instruction to the various lists and dictionaries. 1035 # This is where the sSet and asGroups properties are populated. 1036 # 924 1037 g_aoAllArmInstructions.append(oInstr); 925 1038 assert oInstr.sName not in g_dAllArmInstructionsByName; 926 1039 g_dAllArmInstructionsByName[oInstr.sName] = oInstr; 1040 1041 for oParent in reversed(aoStack): ## @todo reversed? 1042 sName = oParent['name']; 1043 sParentType = oParent['_type']; 1044 if sParentType == "Instruction.InstructionSet": 1045 assert not oInstr.sSet; 1046 oInstr.sSet = sName; 1047 if sName in g_dAllArmInstructionsBySet: 1048 g_dAllArmInstructionsBySet[sName].append(oInstr); 1049 else: 1050 g_dAllArmInstructionsBySet[sName] = [oInstr,]; 1051 elif sParentType == "Instruction.InstructionGroup": 1052 if sName not in oInstr.asGroups: # sve_intx_clamp comes up twice for instance. 1053 oInstr.asGroups.append(sName); 1054 if sName in g_dAllArmInstructionsByGroup: 1055 g_dAllArmInstructionsByGroup[sName].append(oInstr); 1056 else: 1057 g_dAllArmInstructionsByGroup[sName] = [oInstr,]; 1058 else: 1059 raise Exception('Unexpected stack entry type: %s' % (sParentType,)); 1060 927 1061 return True; 928 1062 … … 1066 1200 1067 1201 1068 # 1069 # Pass #2 - Assembly syntax formatting (for display purposes) 1070 # 1071 def asmSymbolsToDisplayText(adSymbols, ddAsmRules, oInstr): 1072 sText = ''; 1073 for dSym in adSymbols: 1074 sType = dSym['_type']; 1075 if sType == 'Instruction.Symbols.Literal': 1076 sText += dSym['value']; 1077 elif sType == 'Instruction.Symbols.RuleReference': 1078 sRuleId = dSym['rule_id']; 1079 sText += asmRuleIdToDisplayText(sRuleId, ddAsmRules, oInstr); 1080 else: 1081 raise Exception('%s: Unknown assembly symbol type: %s' % (oInstr.sMnemonic, sType,)); 1082 return sText; 1083 1084 def asmChoicesFilterOutDefaultAndAbsent(adChoices, ddAsmRules): 1085 # There are sometime a 'none' tail entry. 1086 if adChoices[-1] is None: 1087 adChoices = adChoices[:-1]; 1088 if len(adChoices) > 1: 1089 # Typically, one of the choices is 'absent' or 'default', eliminate it before we start... 1090 for iChoice, dChoice in enumerate(adChoices): 1091 fAllAbsentOrDefault = True; 1092 for dSymbol in dChoice['symbols']: 1093 if dSymbol['_type'] != 'Instruction.Symbols.RuleReference': 1094 fAllAbsentOrDefault = False; 1095 break; 1096 sRuleId = dSymbol['rule_id']; 1097 oRule = ddAsmRules[sRuleId]; 1098 if ( ('display' in oRule and oRule['display']) 1099 or ('symbols' in oRule and oRule['symbols'])): 1100 fAllAbsentOrDefault = False; 1101 break; 1102 if fAllAbsentOrDefault: 1103 return adChoices[:iChoice] + adChoices[iChoice + 1:]; 1104 return adChoices; 1105 1106 def asmRuleIdToDisplayText(sRuleId, ddAsmRules, oInstr): 1107 dRule = ddAsmRules[sRuleId]; 1108 sRuleType = dRule['_type']; 1109 if sRuleType == 'Instruction.Rules.Token': 1110 assert dRule['default'], '%s: %s' % (oInstr.sMnemonic, sRuleId); 1111 return dRule['default']; 1112 if sRuleType == 'Instruction.Rules.Rule': 1113 assert dRule['display'], '%s: %s' % (oInstr.sMnemonic, sRuleId); 1114 return dRule['display']; 1115 if sRuleType == 'Instruction.Rules.Choice': 1116 # Some of these has display = None and we need to sort it out ourselves. 1117 if dRule['display']: 1118 return dRule['display']; 1119 sText = '{'; 1120 assert len(dRule['choices']) > 1; 1121 for iChoice, dChoice in enumerate(asmChoicesFilterOutDefaultAndAbsent(dRule['choices'], ddAsmRules)): 1122 if iChoice > 0: 1123 sText += ' | '; 1124 sText += asmSymbolsToDisplayText(dChoice['symbols'], ddAsmRules, oInstr); 1125 sText += '}'; 1126 1127 # Cache it. 1128 dRule['display'] = sText; 1129 return sText; 1130 1131 raise Exception('%s: Unknown assembly rule type: %s for %s' % (oInstr.sMnemonic, sRuleType, sRuleId)); 1132 1133 def parseInstructionsPass2(aoInstructions, ddAsmRules): 1202 def LoadArmOpenSourceSpecification(oOptions): 1134 1203 """ 1135 Uses the assembly rules to construct some assembly syntax string for each 1136 instruction in the array. 1204 Loads the ARM specifications from a tar file, directory or individual files. 1205 1206 Note! Currently only processes Instructions.json. 1207 1208 @todo Need some reworking as it's taking oOptions as input. It should be 1209 generic and usable by code other than the decoder generator. 1137 1210 """ 1138 for oInstr in aoInstructions: 1139 if 'assembly' in oInstr.oJson: 1140 oAsm = oInstr.oJson['assembly']; 1141 assert oAsm['_type'] == 'Instruction.Assembly'; 1142 assert 'symbols' in oAsm; 1143 oInstr.sAsmDisplay = asmSymbolsToDisplayText(oAsm['symbols'], ddAsmRules, oInstr); 1144 else: 1145 oInstr.sAsmDisplay = oInstr.sMnemonic; 1146 return True; 1147 1148 def LoadArmOpenSourceSpecification(oOptions): 1211 1149 1212 # 1150 1213 # Load the files. … … 1180 1243 # 1181 1244 print("parsing instructions ..."); 1182 # Pass #1: Collect the instructions. 1183 parseInstructions([], dRawInstructions['instructions']); 1184 # Pass #2: Assembly syntax. 1245 global g_oArmInstructionVerInfo; 1246 g_oArmInstructionVerInfo = dRawInstructions['_meta']['version']; 1247 parseInstructions([], dRawInstructions['instructions'], dRawInstructions['assembly_rules']); 1248 1249 # Sort the instruction array by name. 1185 1250 global g_aoAllArmInstructions; 1186 parseInstructionsPass2(g_aoAllArmInstructions, dRawInstructions['assembly_rules']);1187 1188 # Sort the instruction array by name.1189 1251 g_aoAllArmInstructions = sorted(g_aoAllArmInstructions, key = operator.attrgetter('sName', 'sAsmDisplay')); 1190 1252 … … 1834 1896 1835 1897 1836 def generateLicenseHeader(self ):1898 def generateLicenseHeader(self, oVerInfo): 1837 1899 """ 1838 1900 Returns the lines for a license header. … … 1841 1903 '/*', 1842 1904 ' * Autogenerated by $Id$ ', 1905 ' * from the open source %s specs, build %s (%s)' 1906 % (oVerInfo['architecture'], oVerInfo['build'], oVerInfo['ref'],), 1907 ' * dated %s.' % (oVerInfo['timestamp'],), 1908 ' *', 1843 1909 ' * Do not edit!', 1844 1910 ' */', … … 1876 1942 '', 1877 1943 '', 1878 '',1879 1944 ]; 1880 1945 1881 def generateImplementationStub s(self):1946 def generateImplementationStubHdr(self, sFilename, iPartNo): 1882 1947 """ 1883 1948 Generate implementation stubs. 1884 1949 """ 1885 return []; 1950 _ = sFilename; _ = iPartNo; 1951 asLines = self.generateLicenseHeader(g_oArmInstructionVerInfo); 1952 1953 # Organize this by instruction set, groups and instructions. 1954 sPrevCategory = ''; 1955 for oInstr in sorted(g_aoAllArmInstructions, key = operator.attrgetter('sSet', 'asGroups')): 1956 # New group/category? 1957 sCategory = ' / '.join([oInstr.sSet if oInstr.sSet else 'no-instr-set'] + oInstr.asGroups); 1958 if sCategory != sPrevCategory: 1959 asLines += [ 1960 '', 1961 '', 1962 '/*', 1963 ' *', 1964 ' * Instruction Set & Groups: %s' % (sCategory,), 1965 ' *', 1966 ' */', 1967 ]; 1968 sPrevCategory = sCategory; 1969 1970 # Emit the instruction stub. 1971 asArgs = [ # Note! Must match generateDecoderFunctions exactly. 1972 oField.sName for oField in sorted(oInstr.aoEncodesets, key = operator.attrgetter('iFirstBit')) if oField.sName 1973 ]; 1974 asLines += [ 1975 '', 1976 '/* %s (%08x/%08x) */' % (oInstr.sAsmDisplay, oInstr.fFixedMask, oInstr.fFixedValue,), 1977 '//#define IEM_INSTR_IMPL__%s(%s) ' % (oInstr.getCName(), ', '.join(asArgs)), 1978 '', 1979 ] 1980 1981 return (True, asLines); 1886 1982 1887 1983 def generateDecoderFunctions(self): … … 1920 2016 asLines += [ 1921 2017 '', 1922 '/* %08x/%08x: %s */' % (oInstr.fFixedMask, oInstr.fFixedValue, oInstr.sAsmDisplay,), 2018 '/* %08x/%08x: %s' % (oInstr.fFixedMask, oInstr.fFixedValue, oInstr.sAsmDisplay,), 2019 ' Instruction Set: %s%s%s */' 2020 % (oInstr.sSet, ' Group: ' if oInstr.asGroups else '', ','.join(oInstr.asGroups),), 1923 2021 'FNIEMOP_DEF_1(iemDecodeA64_%s, uint32_t, uOpcode)' % (sCName,), 1924 2022 '{', … … 1971 2069 asLines += [ 1972 2070 '%s LogFlow(("%%010x: %s%s\\n",%s));' % (sIndent, sCName, sLogFmt, ', '.join(['uOpcode',] + asArgs),), 1973 '#ifdef HAS_IMPL_%s' % (sCName,),1974 '%s return iemImpl_%s(%s);' % (sIndent, sCName, ', '.join(['pVCpu',] +asArgs),),2071 '#ifdef IEM_INSTR_IMPL__%s' % (sCName,), 2072 '%s IEM_INSTR_IMPL__%s(%s);' % (sIndent, sCName, ', '.join(asArgs),), 1975 2073 '#else', 1976 2074 '%s RT_NOREF(%s);' % (sIndent, ', '.join(asArgs + ['pVCpu', 'uOpcode',]),), … … 2109 2207 """ Generates the decoder data & code. """ 2110 2208 _ = iPartNo; _ = sFilename; 2111 asLines = self.generateLicenseHeader( );2112 asLines .extend([2209 asLines = self.generateLicenseHeader(g_oArmInstructionVerInfo); 2210 asLines += [ 2113 2211 '#define LOG_GROUP LOG_GROUP_IEM', 2114 2212 '#define VMCPU_INCL_CPUM_GST_CTX', … … 2128 2226 ' IEMOP_RAISE_INVALID_OPCODE_RET();', 2129 2227 '}', 2130 ] );2228 ]; 2131 2229 2132 2230 asLines += self.generateDecoderFunctions(); … … 2141 2239 _ = iPartNo; 2142 2240 2143 asLines = self.generateLicenseHeader( );2241 asLines = self.generateLicenseHeader(g_oArmInstructionVerInfo); 2144 2242 sBlockerName = re.sub('[.-]', '_', os.path.basename(sFilename)); 2145 2243 asLines += [ … … 2215 2313 oArgParser.add_argument('--out-decoder-hdr', 2216 2314 metavar = 'file-decoder.h', 2217 dest = 'sFileDecoderH ',2315 dest = 'sFileDecoderHdr', 2218 2316 action = 'store', 2219 2317 default = '-', 2220 2318 help = 'The output header file for the decoder.'); 2319 oArgParser.add_argument('--out-stub-hdr', 2320 metavar = 'file-stub.h', 2321 dest = 'sFileStubHdr', 2322 action = 'store', 2323 default = '-', 2324 help = 'The output header file for the implementation stubs.'); 2221 2325 # debug: 2222 2326 oArgParser.add_argument('--print-instructions', … … 2252 2356 aaoOutputFiles = [ 2253 2357 ( oOptions.sFileDecoderCpp, self.generateDecoderCpp, 0, ), 2254 ( oOptions.sFileDecoderH, self.generateDecoderHdr, 0, ), # Must be after generateDecoderCpp! 2358 ( oOptions.sFileDecoderHdr, self.generateDecoderHdr, 0, ), # Must be after generateDecoderCpp! 2359 ( oOptions.sFileStubHdr, self.generateImplementationStubHdr, 0, ), 2255 2360 ]; 2256 2361 fRc = True;
Note:
See TracChangeset
for help on using the changeset viewer.