VirtualBox

Changeset 108853 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Apr 4, 2025 2:27:50 PM (5 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
168303
Message:

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

File:
1 edited

Legend:

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

    r108848 r108853  
    150150    def fromJson(oJson):
    151151        """ Decodes an AST/Values expression. """
    152         print('debug ast: %s' % oJson['_type'])
     152        #print('debug ast: %s' % oJson['_type'])
    153153        return ArmAstBase.kfnTypeMap[oJson['_type']](oJson);
    154154
     
    178178        self.oRight = oRight;
    179179
     180        # Switch value == field non-sense (simplifies transferConditionsToEncoding and such):
     181        if (    isinstance(oRight, ArmAstIdentifier)
     182            and isinstance(oLeft, [ArmAstValue, ArmAstInteger])
     183            and sOp in ['==', '!=']):
     184            self.oLeft  = oRight;
     185            self.oRight = oLeft;
     186
     187    @staticmethod
     188    def needParentheses(oNode, sOp = '&&'):
     189        if isinstance(oNode, ArmAstBinaryOp):
     190            if sOp != '&&'  or  oNode.sOp in ('||', '+'):
     191                return True;
     192        return False;
     193
     194    def toString(self):
     195        sLeft = self.oLeft.toString();
     196        if ArmAstBinaryOp.needParentheses(self.oLeft, self.sOp):
     197            sLeft = '(%s)' % (sLeft);
     198
     199        sRight = self.oRight.toString();
     200        if ArmAstBinaryOp.needParentheses(self.oRight, self.sOp):
     201            sRight = '(%s)' % (sRight);
     202
     203        return '%s %s %s' % (sLeft, self.sOp, sRight);
    180204
    181205class ArmAstUnaryOp(ArmAstBase):
     
    191215        self.oExpr = oExpr;
    192216
     217    def toString(self):
     218        if ArmAstBinaryOp.needParentheses(self.oExpr):
     219            return '%s(%s)' % (self.sOp, self.oExpr.toString(),);
     220        return '%s%s' % (self.sOp, self.oExpr.toString(),);
    193221
    194222class ArmAstSquareOp(ArmAstBase):
     
    197225        self.aoValues = aoValues;
    198226
     227    def toString(self):
     228        return '<%s>' % (','.join([oValue.toString() for oValue in self.aoValues]),);
     229
    199230
    200231class ArmAstConcat(ArmAstBase):
     
    203234        self.aoValues = aoValues;
    204235
     236    def toString(self):
     237        sRet = '';
     238        for oValue in self.aoValues:
     239            if sRet:
     240                sRet += ':'
     241            if isinstance(oValue, ArmAstIdentifier):
     242                sRet += oValue.sName;
     243            else:
     244                sRet += '(%s)' % (oValue.toString());
     245        return sRet;
    205246
    206247class ArmAstFunction(ArmAstBase):
     
    210251        ArmAstBase.__init__(self, ArmAstBase.kTypeFunction);
    211252        assert self.s_oReValidName.match(sName), 'sName=%s' % (sName);
    212         self.sName    = sName;
    213         self.aoValues = aoArgs;
    214 
     253        self.sName  = sName;
     254        self.aoArgs = aoArgs;
     255
     256    def toString(self):
     257        return '%s(%s)' % (self.sName, ','.join([oArg.toString() for oArg in self.aoArgs]),);
    215258
    216259class ArmAstIdentifier(ArmAstBase):
     
    222265        self.sName = sName;
    223266
     267    def toString(self):
     268        return self.sName;
    224269
    225270class ArmAstBool(ArmAstBase):
     
    229274        self.fValue = fValue;
    230275
     276    def toString(self):
     277        return 'true' if self.fValue is True else 'false';
     278
    231279
    232280class ArmAstInteger(ArmAstBase):
     
    235283        self.iValue = int(iValue);
    236284
     285    def toString(self):
     286        return '%#x' % (self.iValue,);
    237287
    238288class ArmAstSet(ArmAstBase):
     
    241291        self.aoValues = aoValues;
    242292
     293    def toString(self):
     294        return '(%s)' % (', '.join([oValue.toString() for oValue in self.aoValues]),);
    243295
    244296class ArmAstValue(ArmAstBase):
     
    246298        ArmAstBase.__init__(self, ArmAstBase.kTypeValue);
    247299        self.sValue = sValue;
     300
     301    def toString(self):
     302        return self.sValue;
    248303
    249304
     
    284339
    285340    @staticmethod
    286     def fromJson(oJson):
    287         """ """
    288         assert oJson['_type'] in ('Instruction.Encodeset.Field', 'Instruction.Encodeset.Bits'), oJson['_type'];
    289 
    290         oRange = oJson['range'];
    291         assert oRange['_type'] == 'Range';
    292         iFirstBit  = int(oRange['start']);
    293         cBitsWidth = int(oRange['width']);
    294 
    295         sValue = oJson['value']['value'];
     341    def parseValue(sValue, cBitsWidth):
     342        """
     343        Returns (fValue, fFixed) tuple on success, raises AssertionError otherwise.
     344        """
    296345        assert sValue[0] == '\'' and sValue[-1] == '\'', sValue;
    297346        sValue = sValue[1:-1];
     
    307356                if ch == '1':
    308357                    fValue |= 1;
    309 
    310         sName = oJson['name'] if oJson['_type'] == 'Instruction.Encodeset.Field' else None;
     358        return (fValue, fFixed);
     359
     360    @staticmethod
     361    def fromJson(oJson):
     362        """ """
     363        assert oJson['_type'] in ('Instruction.Encodeset.Field', 'Instruction.Encodeset.Bits'), oJson['_type'];
     364
     365        oRange = oJson['range'];
     366        assert oRange['_type'] == 'Range';
     367        iFirstBit        = int(oRange['start']);
     368        cBitsWidth       = int(oRange['width']);
     369        sName            = oJson['name'] if oJson['_type'] == 'Instruction.Encodeset.Field' else None;
     370        (fValue, fFixed) = ArmEncodesetField.parseValue(oJson['value']['value'], cBitsWidth);
    311371        return ArmEncodesetField(oJson, iFirstBit, cBitsWidth, fFixed, fValue, sName);
    312372
     
    384444            parseInstructions([oJson,] + aoStack, oJson['children']);
    385445        elif oJson['_type'] == "Instruction.Instruction":
     446            sInstrNm = oJson['name'];
     447
    386448            (aoEncodesets, fCovered) = ArmEncodesetField.fromJsonEncodeset(oJson['encoding'], [], 0);
    387449            for oParent in aoStack:
    388450                if 'encoding' in oParent:
    389451                    (aoEncodesets, fCovered) = ArmEncodesetField.fromJsonEncodeset(oParent['encoding'], aoEncodesets, fCovered);
     452
    390453            oCondition = ArmAstBase.fromJson(oJson['condition']);
    391             oInstr = ArmInstruction(oJson, oJson['name'], oJson['name'], aoEncodesets, oCondition);
     454            print('debug transfer in:  %s' % (oCondition.toString()));
     455            (oCondition, fMod) = transferConditionsToEncoding(oCondition, aoEncodesets, collections.defaultdict(list), sInstrNm);
     456            if fMod:
     457                print('debug transfer out: %s' % (oCondition.toString()));
     458
     459            oInstr = ArmInstruction(oJson, sInstrNm, sInstrNm, aoEncodesets, oCondition);
    392460
    393461            g_aoAllArmInstructions.append(oInstr);
     
    395463            g_dAllArmInstructionsByName[oInstr.sName] = oInstr;
    396464    return True;
     465
     466def transferConditionsToEncoding(oCondition, aoEncodesets, dPendingNotEq, sInstrNm, uDepth = 0, fMod = False):
     467    """
     468    This is for dealing with stuff like asr_z_p_zi_ and lsr_z_p_zi_ which has
     469    the same fixed encoding fields in the specs, but differs in the value of
     470    the named field 'U' as expressed in the conditions.
     471
     472    This function will recursively take 'Field == value/integer' expression out
     473    of the condition tree and add them to the encodeset conditions when possible.
     474
     475    The dPendingNotEq stuff is a hack to deal with stuff like this:
     476        sdot_z_zzz_:     U == '0' && size != '01' && size != '00'
     477                     && (IsFeatureImplemented(FEAT_SVE) || IsFeatureImplemented(FEAT_SME))
     478    The checks can be morphed into the 'size' field encoding criteria as '0b0x'.
     479    """
     480    def isBoolTrue(oNode):
     481        return isinstance(oNode, ArmAstBool) and oNode.fValue is True;
     482
     483    if isinstance(oCondition, ArmAstBinaryOp):
     484        if oCondition.sOp == '&&':
     485            print('debug transfer: %s: recursion...' % (sInstrNm,));
     486            # Recurse into each side of an AND expression.
     487            (oCondition.oLeft, fMod)  = transferConditionsToEncoding(oCondition.oLeft,  aoEncodesets, dPendingNotEq,
     488                                                                     sInstrNm, uDepth + 1, fMod);
     489            (oCondition.oRight, fMod) = transferConditionsToEncoding(oCondition.oRight, aoEncodesets, dPendingNotEq,
     490                                                                     sInstrNm, uDepth + 1, fMod);
     491            if isBoolTrue(oCondition.oLeft):
     492                return (oCondition.oRight, fMod);
     493            if isBoolTrue(oCondition.oRight):
     494                return (oCondition.oLeft, fMod);
     495
     496        elif oCondition.sOp in ('==', '!='):
     497            # 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));
     499            if (    isinstance(oCondition.oLeft, ArmAstIdentifier)
     500                and isinstance(oCondition.oRight, (ArmAstValue, ArmAstInteger))):
     501                sFieldName = oCondition.oLeft.sName;
     502                oValue     = oCondition.oRight;
     503                print('debug transfer: %s: binaryop step 2...' % (sInstrNm,));
     504                for oField in aoEncodesets: # ArmEncodesetField
     505                    if oField.sName and oField.sName == sFieldName:
     506                        # ArmAstInteger (unlikely):
     507                        if isinstance(oValue, ArmAstInteger):
     508                            if oField.fFixed != 0:
     509                                raise Exception('%s: Condition checks fixed field value: %s (%#x/%#x) %s %s'
     510                                                % (sInstrNm, oField.sName, oField.fValue, oField.fFixed,
     511                                                   oCondition.sOp, oValue.iValue,));
     512                            assert oField.fValue == 0;
     513                            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)'
     515                                                % (sInstrNm, oField.sName, oField.cBitsWidth, oValue.iValue,
     516                                                   oValue.iValue.bit_count(),));
     517                            if oValue.iValue < 0:
     518                                raise Exception('%s: Condition field checks against negative value: %s, test value is %s'
     519                                                % (sInstrNm, oField.sName, oValue.iValue));
     520                            fFixed = (1 << oField.cBitsWidth) - 1;
     521                            if oCondition.sOp == '!=' and oField.cBitsWidth > 1:
     522                                dPendingNotEq[oField.sName] += [(oField, oValue.iValue, fFixed, oCondition)];
     523                                break;
     524
     525                            print('debug transfer: %s: integer binaryop -> encoding!' % (sInstrNm,));
     526                            if oCondition.sOp == '==':
     527                                oField.fValue = oValue.iValue;
     528                            else:
     529                                oField.fValue = ~oValue.iValue & fFixed;
     530                            oField.fFixed = fFixed;
     531                            return (ArmAstBool(True), True);
     532
     533                        # ArmAstValue.
     534                        assert isinstance(oValue, ArmAstValue);
     535                        (fValue, fFixed) = ArmEncodesetField.parseValue(oValue.sValue, oField.cBitsWidth);
     536
     537                        if oCondition.sOp == '!=' and oField.cBitsWidth > 1 and (fFixed & (fFixed - 1)) != 0:
     538                            dPendingNotEq[oField.sName] += [(oField, fValue, fFixed, oCondition)];
     539                            break;
     540                        if fFixed & oField.fFixed:
     541                            raise Exception('%s: Condition checks fixed field value: %s (%#x/%#x) %s %s (%#x/%#x)'
     542                                            % (sInstrNm, oField.sName, oField.fValue, oField.fFixed, oCondition.sOp,
     543                                               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,));
     546                        if oCondition.sOp == '==':
     547                            oField.fValue |= fValue;
     548                        else:
     549                            oField.fValue |= ~fValue & fFixed;
     550                        oField.fFixed |= fFixed;
     551                        return (ArmAstBool(True), True);
     552
     553    #
     554    # Deal with pending '!=' optimizations for fields larger than a single bit.
     555    # Currently we only deal with two bit fields.
     556    #
     557    if uDepth == 0 and dPendingNotEq:
     558        for sFieldNm, atOccurences in dPendingNotEq.items():
     559            # For a two bit field, we need at least two occurences to get any kind of fixed value.
     560            oField = atOccurences[0][0];
     561            if oField.cBitsWidth == 2 and len(atOccurences) >= 2:
     562                dValues = {};
     563                dFixed  = {};
     564                for oCurField, fValue, fFixed, _ in atOccurences:
     565                    assert oCurField is oField;
     566                    dValues[fValue] = 1;
     567                    dFixed[fFixed]  = 1;
     568                if len(dValues) in (2, 3) and len(dFixed) == 1 and 3 in dFixed:
     569                    afValues = list(dValues);
     570                    if len(dValues) == 2:
     571                        fFixed = 2 if (afValues[0] ^ afValues[1]) & 1 else 1; # One of the bits are fixed, the other ignored.
     572                    else:
     573                        fFixed = 3;                                           # Both bits are fixed.
     574                    fValue = afValues[0] & fFixed;
     575                    print('debug transfer: %s: %u binaryops -> encoding! %s != %#x/%#x'
     576                          % (sInstrNm, len(atOccurences), oField.sName, fValue, fFixed,));
     577
     578                    # 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);
     594                    fMod = True;
     595                else:
     596                    print('info: %s: transfer cond to enc failed for: %s dValues=%s dFixed=%s'
     597                          % (sInstrNm, oField.sName, dValues, dFixed));
     598            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,));
     600
     601    return (oCondition, fMod);
     602
    397603
    398604#
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