VirtualBox

Changeset 108916 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Apr 9, 2025 11:32:33 AM (4 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
168397
Message:

VMM/IEM: Working on the ARM bsd/opensource spec reader & decoder generator. Mostly there. jiraref:VBP-1598

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/target-armv8/bsd-spec-analyze.py

    r108904 r108916  
    836836    s_oReValidName = re.compile('^[_A-Za-z][_A-Za-z0-9]+$');
    837837
    838     def __init__(self, oJson, sName, sMemonic, aoEncodesets, oCondition):
     838    def __init__(self, oJson, sName, sMemonic, sAsmDisplay, aoEncodesets, oCondition):
    839839        assert self.s_oReValidName.match(sName), 'sName=%s' % (sName);
    840840        self.oJson           = oJson;
    841841        self.sName           = sName;
    842842        self.sMnemonic       = sMemonic;
    843         self.sAsmDisplay     = '';
     843        self.sAsmDisplay     = sAsmDisplay;
     844        self.sSet            = None;
     845        self.asGroups        = [];
    844846        self.aoEncodesets    = aoEncodesets;
    845847        self.oCondition      = oCondition;
     
    889891#
    890892
     893## The '_meta::version' dictionary from the Instructions.json file.
     894g_oArmInstructionVerInfo = None;
     895
    891896## All the instructions.
    892897g_aoAllArmInstructions = []             # type: List[ArmInstruction]
    893898
    894 ## All the instructions by name (not mnemonic.
     899## All the instructions by name (not mnemonic).
    895900g_dAllArmInstructionsByName = {}        # type: Dict[ArmInstruction]
    896901
    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.
     903g_dAllArmInstructionsBySet = {}         # type: Dict[List[ArmInstruction]]
     904
     905## All the instruction by instruction group name.
     906g_dAllArmInstructionsByGroup = {}       # type: Dict[List[ArmInstruction]]
     907
     908
     909def __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
     938def __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
     969def 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
     987def parseInstructions(aoStack, aoJson, ddAsmRules):
    901988    for oJson in aoJson:
    902989        if oJson['_type'] == "Instruction.InstructionSet":
    903             parseInstructions([oJson,] + aoStack, oJson['children']);
     990            assert oJson['name'];
     991            parseInstructions([oJson,] + aoStack, oJson['children'], ddAsmRules);
     992
    904993        elif oJson['_type'] == "Instruction.InstructionGroup":
    905             parseInstructions([oJson,] + aoStack, oJson['children']);
     994            assert oJson['name'];
     995            parseInstructions([oJson,] + aoStack, oJson['children'], ddAsmRules);
     996
    906997        elif oJson['_type'] == "Instruction.Instruction":
     998            #
     999            # Start by getting the instruction attributes.
     1000            #
    9071001            sInstrNm = oJson['name'];
    9081002
     
    9201014            _ = fMod;
    9211015
    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            #
    9241037            g_aoAllArmInstructions.append(oInstr);
    9251038            assert oInstr.sName not in g_dAllArmInstructionsByName;
    9261039            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
    9271061    return True;
    9281062
     
    10661200
    10671201
    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):
     1202def LoadArmOpenSourceSpecification(oOptions):
    11341203    """
    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.
    11371210    """
    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
    11491212    #
    11501213    # Load the files.
     
    11801243    #
    11811244    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.
    11851250    global g_aoAllArmInstructions;
    1186     parseInstructionsPass2(g_aoAllArmInstructions, dRawInstructions['assembly_rules']);
    1187 
    1188     # Sort the instruction array by name.
    11891251    g_aoAllArmInstructions = sorted(g_aoAllArmInstructions, key = operator.attrgetter('sName', 'sAsmDisplay'));
    11901252
     
    18341896
    18351897
    1836     def generateLicenseHeader(self):
     1898    def generateLicenseHeader(self, oVerInfo):
    18371899        """
    18381900        Returns the lines for a license header.
     
    18411903            '/*',
    18421904            ' * 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            ' *',
    18431909            ' * Do not edit!',
    18441910            ' */',
     
    18761942            '',
    18771943            '',
    1878             '',
    18791944        ];
    18801945
    1881     def generateImplementationStubs(self):
     1946    def generateImplementationStubHdr(self, sFilename, iPartNo):
    18821947        """
    18831948        Generate implementation stubs.
    18841949        """
    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);
    18861982
    18871983    def generateDecoderFunctions(self):
     
    19202016            asLines += [
    19212017                '',
    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),),
    19232021                'FNIEMOP_DEF_1(iemDecodeA64_%s, uint32_t, uOpcode)' % (sCName,),
    19242022                '{',
     
    19712069            asLines += [
    19722070                '%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),),
    19752073                '#else',
    19762074                '%s    RT_NOREF(%s);' % (sIndent, ', '.join(asArgs + ['pVCpu', 'uOpcode',]),),
     
    21092207        """ Generates the decoder data & code. """
    21102208        _ = iPartNo; _ = sFilename;
    2111         asLines = self.generateLicenseHeader();
    2112         asLines.extend([
     2209        asLines = self.generateLicenseHeader(g_oArmInstructionVerInfo);
     2210        asLines += [
    21132211            '#define LOG_GROUP LOG_GROUP_IEM',
    21142212            '#define VMCPU_INCL_CPUM_GST_CTX',
     
    21282226            '    IEMOP_RAISE_INVALID_OPCODE_RET();',
    21292227            '}',
    2130         ]);
     2228        ];
    21312229
    21322230        asLines += self.generateDecoderFunctions();
     
    21412239        _ = iPartNo;
    21422240
    2143         asLines = self.generateLicenseHeader();
     2241        asLines = self.generateLicenseHeader(g_oArmInstructionVerInfo);
    21442242        sBlockerName = re.sub('[.-]', '_', os.path.basename(sFilename));
    21452243        asLines += [
     
    22152313        oArgParser.add_argument('--out-decoder-hdr',
    22162314                                metavar = 'file-decoder.h',
    2217                                 dest    = 'sFileDecoderH',
     2315                                dest    = 'sFileDecoderHdr',
    22182316                                action  = 'store',
    22192317                                default = '-',
    22202318                                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.');
    22212325        # debug:
    22222326        oArgParser.add_argument('--print-instructions',
     
    22522356            aaoOutputFiles = [
    22532357                 ( 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, ),
    22552360            ];
    22562361            fRc = True;
Note: See TracChangeset for help on using the changeset viewer.

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