VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/target-armv8/bsd-spec-analyze.py@ 108413

Last change on this file since 108413 was 108246, checked in by vboxsync, 3 months ago

VMM/IEM: Splitting up IEMAll.cpp. jiraref:VBP-1531

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: bsd-spec-analyze.py 108246 2025-02-17 00:18:01Z vboxsync $
4
5"""
6ARM BSD specification analyser.
7"""
8
9from __future__ import print_function;
10
11__copyright__ = \
12"""
13Copyright (C) 2025 Oracle and/or its affiliates.
14
15This file is part of VirtualBox base platform packages, as
16available from https://www.215389.xyz.
17
18This program is free software; you can redistribute it and/or
19modify it under the terms of the GNU General Public License
20as published by the Free Software Foundation, in version 3 of the
21License.
22
23This program is distributed in the hope that it will be useful, but
24WITHOUT ANY WARRANTY; without even the implied warranty of
25MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with this program; if not, see <https://www.gnu.org/licenses>.
30
31SPDX-License-Identifier: GPL-3.0-only
32"""
33__version__ = "$Revision: 108246 $"
34
35# Standard python imports.
36import argparse;
37import collections;
38import json;
39import os;
40import sys;
41import tarfile;
42
43
44class ArmEncodesetField(object):
45 """
46 ARM Encodeset.Bits & Encodeset.Field.
47 """
48 def __init__(self, oJson, iFirstBit, cBitsWidth, fFixed, fValue, sName = None):
49 self.oJson = oJson;
50 self.iFirstBit = iFirstBit;
51 self.cBitsWidth = cBitsWidth;
52 self.fFixed = fFixed;
53 self.fValue = fValue;
54 self.sName = sName; ##< None if Encodeset.Bits.
55
56 def __str__(self):
57 sRet = '[%2u:%-2u] = %#x/%#x/%#x' % (
58 self.iFirstBit + self.cBitsWidth - 1, self.iFirstBit, self.fValue, self.fFixed, self.getMask()
59 );
60 if self.sName:
61 sRet += ' # %s' % (self.sName,)
62 return sRet;
63
64 def __repr__(self):
65 return self.__str__();
66
67 def getMask(self):
68 """ Field mask (unshifted). """
69 return (1 << self.cBitsWidth) - 1;
70
71 def getShiftedMask(self):
72 """ Field mask, shifted. """
73 return ((1 << self.cBitsWidth) - 1) << self.iFirstBit;
74
75 @staticmethod
76 def fromJson(oJson):
77 """ """
78 assert oJson['_type'] in ('Instruction.Encodeset.Field', 'Instruction.Encodeset.Bits'), oJson['_type'];
79
80 oRange = oJson['range'];
81 assert oRange['_type'] == 'Range';
82 iFirstBit = int(oRange['start']);
83 cBitsWidth = int(oRange['width']);
84
85 sValue = oJson['value']['value'];
86 assert sValue[0] == '\'' and sValue[-1] == '\'', sValue;
87 sValue = sValue[1:-1];
88 assert len(sValue) == cBitsWidth, 'cBitsWidth=%s sValue=%s' % (cBitsWidth, sValue,);
89 fFixed = 0;
90 fValue = 0;
91 for ch in sValue:
92 assert ch in 'x10', 'ch=%s' % ch;
93 fFixed <<= 1;
94 fValue <<= 1;
95 if ch != 'x':
96 fFixed |= 1;
97 if ch == '1':
98 fValue |= 1;
99
100 sName = oJson['name'] if oJson['_type'] == 'Instruction.Encodeset.Field' else None;
101 return ArmEncodesetField(oJson, iFirstBit, cBitsWidth, fFixed, fValue, sName);
102
103 @staticmethod
104 def fromJsonEncodeset(oJson, aoSet, fCovered):
105 """ """
106 assert oJson['_type'] == 'Instruction.Encodeset.Encodeset', oJson['_type'];
107 for oJsonValue in oJson['values']:
108 oNewField = ArmEncodesetField.fromJson(oJsonValue);
109 fNewMask = oNewField.getShiftedMask();
110 if (fNewMask & fCovered) != fNewMask:
111 aoSet.append(oNewField)
112 fCovered |= fNewMask;
113 return (aoSet, fCovered);
114
115
116class ArmInstruction(object):
117 """
118 ARM instruction
119 """
120 def __init__(self, oJson, sName, sMemonic, aoEncodesets):
121 self.oJson = oJson;
122 self.sName = sName;
123 self.sMnemonic = sMemonic;
124 self.aoEncodesets = aoEncodesets;
125 self.fFixedMask = 0;
126 self.fFixedValue = 0;
127 for oField in aoEncodesets:
128 self.fFixedMask |= oField.fFixed << oField.iFirstBit;
129 self.fFixedValue |= oField.fValue << oField.iFirstBit;
130
131 def __str__(self):
132 sRet = 'sName=%s; sMnemonic=%s fFixedValue/Mask=%#x/%#x encoding=\n %s' % (
133 self.sName, self.sMnemonic, self.fFixedValue, self.fFixedMask,
134 ',\n '.join([str(s) for s in self.aoEncodesets]),
135 );
136 return sRet;
137
138 def __repr__(self):
139 return self.__str__();
140
141## All the instructions.
142g_aoAllArmInstructions = [] # type: List[ArmInstruction]
143
144## All the instructions by name (not mnemonic.
145g_dAllArmInstructionsByName = {} # type: Dict[ArmInstruction]
146
147
148def parseInstructions(aoStack, aoJson):
149 for oJson in aoJson:
150 if oJson['_type'] == "Instruction.InstructionSet":
151 parseInstructions([oJson,] + aoStack, oJson['children']);
152 elif oJson['_type'] == "Instruction.InstructionGroup":
153 parseInstructions([oJson,] + aoStack, oJson['children']);
154 elif oJson['_type'] == "Instruction.Instruction":
155 #aoJsonEncodings = [oJson['encoding'],];
156 (aoEncodesets, fCovered) = ArmEncodesetField.fromJsonEncodeset(oJson['encoding'], [], 0);
157 for oParent in aoStack:
158 if 'encoding' in oParent:
159 (aoEncodesets, fCovered) = ArmEncodesetField.fromJsonEncodeset(oParent['encoding'], aoEncodesets, fCovered);
160 oInstr = ArmInstruction(oJson, oJson['name'], oJson['name'], aoEncodesets);
161
162 g_aoAllArmInstructions.append(oInstr);
163 assert oInstr.sName not in g_dAllArmInstructionsByName;
164 g_dAllArmInstructionsByName[oInstr.sName] = oInstr;
165
166
167def bsdSpecAnalysis(asArgs):
168 """ Main function. """
169
170 #
171 # Parse arguments.
172 #
173 oArgParser = argparse.ArgumentParser(add_help = False);
174 oArgParser.add_argument('--tar',
175 metavar = 'AARCHMRS_BSD_A_profile-2024-12.tar.gz',
176 dest = 'sTarFile',
177 action = 'store',
178 default = None,
179 help = 'Specification TAR file to get the files from.');
180 oArgParser.add_argument('--instructions',
181 metavar = 'Instructions.json',
182 dest = 'sFileInstructions',
183 action = 'store',
184 default = 'Instructions.json',
185 help = 'The path to the instruction specficiation file.');
186 oArgParser.add_argument('--features',
187 metavar = 'Features.json',
188 dest = 'sFileFeatures',
189 action = 'store',
190 default = 'Features.json',
191 help = 'The path to the features specficiation file.');
192 oArgParser.add_argument('--registers',
193 metavar = 'Registers.json',
194 dest = 'sFileRegisters',
195 action = 'store',
196 default = 'Registers.json',
197 help = 'The path to the registers specficiation file.');
198 oArgParser.add_argument('--spec-dir',
199 metavar = 'dir',
200 dest = 'sSpecDir',
201 action = 'store',
202 default = '',
203 help = 'Specification directory to prefix the specficiation files with.');
204 oOptions = oArgParser.parse_args(asArgs[1:]);
205
206 #
207 # Load the files.
208 #
209 print("loading specs ...");
210 if oOptions.sTarFile:
211 with tarfile.open(oOptions.sTarFile, 'r') as oTarFile:
212 with oTarFile.extractfile(oOptions.sFileInstructions) as oFile:
213 dRawInstructions = json.load(oFile);
214 #with open(sFileFeatures, 'r', encoding = 'utf-8') as oFile:
215 # dRawFeatures = json.load(oFile);
216 #with open(sFileRegisters, 'r', encoding = 'utf-8') as oFile:
217 # dRawRegisters = json.load(oFile);
218 else:
219 if oOptions.sSpecDir:
220 if not os.path.isabs(oOptions.sFileInstructions):
221 oOptions.sFileInstructions = os.path.normpath(os.path.join(oOptions.sSpecDir, oOptions.sFileInstructions));
222 if not os.path.isabs(oOptions.sFileFeatures):
223 oOptions.sFileFeatures = os.path.normpath(os.path.join(oOptions.sSpecDir, oOptions.sFileFeatures));
224 if not os.path.isabs(oOptions.sFileRegisters):
225 oOptions.sFileRegisters = os.path.normpath(os.path.join(oOptions.sSpecDir, oOptions.sFileRegisters));
226
227 with open(oOptions.sFileInstructions, 'r', encoding = 'utf-8') as oFile:
228 dRawInstructions = json.load(oFile);
229 #with open(oOptions.sFileFeatures, 'r', encoding = 'utf-8') as oFile:
230 # dRawFeatures = json.load(oFile);
231 #with open(oOptions.sFileRegisters, 'r', encoding = 'utf-8') as oFile:
232 # dRawRegisters = json.load(oFile);
233 print("... done loading.");
234
235 #
236 # Parse the Instructions.
237 #
238 print("parsing instructions ...");
239 parseInstructions([], dRawInstructions['instructions']);
240 print("Found %u instructions." % (len(g_aoAllArmInstructions),));
241
242 #oBrk = g_dAllArmInstructionsByName['BRK_EX_exception'];
243 #print("oBrk=%s" % (oBrk,))
244
245 if False:
246 for oInstr in g_aoAllArmInstructions:
247 print('%08x/%08x %s' % (oInstr.fFixedMask, oInstr.fFixedValue, oInstr.sName));
248
249 # Gather stats on fixed bits:
250 if True:
251 dCounts = collections.Counter();
252 for oInstr in g_aoAllArmInstructions:
253 cPopCount = bin(oInstr.fFixedMask).count('1');
254 dCounts[cPopCount] += 1;
255
256 print('');
257 print('Fixed bit pop count distribution:');
258 for i in range(33):
259 if i in dCounts:
260 print(' %2u: %u' % (i, dCounts[i]));
261
262 # Top 10 fixed masks.
263 if True:
264 dCounts = collections.Counter();
265 for oInstr in g_aoAllArmInstructions:
266 dCounts[oInstr.fFixedMask] += 1;
267
268 print('');
269 print('Top 20 fixed masks:');
270 for fFixedMask, cHits in dCounts.most_common(20):
271 print(' %#x: %u times' % (fFixedMask, cHits,));
272
273 return 0;
274
275
276if __name__ == '__main__':
277 sys.exit(bsdSpecAnalysis(sys.argv));
278
Note: See TracBrowser for help on using the repository browser.

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