11import os
22import re
33import sys
4+ import yaml
45from collections import defaultdict
56
67def parse_header_files (header_files ):
@@ -188,29 +189,65 @@ def format_encoding(encoding_str):
188189 formatted_str = f"{ group1 } { group2 } { group3 } { group4 } { group5 } "
189190 return formatted_str
190191
191- def get_instruction_names_from_directory (directory_path ):
192+ def get_instruction_yaml_files (directory_path ):
192193 """
193- Lists all .yaml files in the specified directory and extracts instruction names.
194+ Recursively finds all .yaml files in the specified directory and its subdirectories,
195+ and maps instruction names to their YAML file paths.
194196
195197 Args:
196198 directory_path (str): Path to the directory containing YAML files.
197199
198200 Returns:
199- instr_names (set ): A set of instruction names without the .yaml extension .
201+ instr_yaml_map (dict ): Mapping from instruction name to YAML file path .
200202 """
201- try :
202- files = os .listdir (directory_path )
203- except FileNotFoundError :
204- print (f"Error: Directory '{ directory_path } ' not found." )
205- return set ()
203+ instr_yaml_map = {}
204+ for root , dirs , files in os .walk (directory_path ):
205+ for file in files :
206+ if file .endswith ('.yaml' ):
207+ instr_name = os .path .splitext (file )[0 ]
208+ yaml_path = os .path .join (root , file )
209+ if instr_name in instr_yaml_map :
210+ print (f"Warning: Multiple YAML files found for instruction '{ instr_name } '. "
211+ f"Using '{ instr_yaml_map [instr_name ]} ' and ignoring '{ yaml_path } '." )
212+ else :
213+ instr_yaml_map [instr_name ] = yaml_path
214+ return instr_yaml_map
215+
216+ def parse_yaml_encoding (yaml_file_path ):
217+ """
218+ Parses the YAML file to extract the 'encoding: match' string.
206219
207- instr_names = set ()
208- for file in files :
209- if file .endswith ('.yaml' ):
210- instr_name = os .path .splitext (file )[0 ]
211- instr_names .add (instr_name )
220+ Args:
221+ yaml_file_path (str): Path to the YAML file.
212222
213- return instr_names
223+ Returns:
224+ match_encoding (str): The 32-character match encoding string.
225+ """
226+ try :
227+ with open (yaml_file_path , 'r' ) as yaml_file :
228+ yaml_content = yaml .safe_load (yaml_file )
229+ if not isinstance (yaml_content , dict ) or not yaml_content :
230+ print (f"Warning: YAML file '{ yaml_file_path } ' is empty or not properly formatted." )
231+ return ''
232+
233+ # Assuming the YAML structure has the instruction name as the top key
234+ # and 'encoding' as a subkey
235+ # Example:
236+ # add:
237+ # encoding:
238+ # match: "0000000----------000-----0110011"
239+ instr_name = list (yaml_content .keys ())[0 ]
240+ encoding = yaml_content [instr_name ].get ('encoding' , {})
241+ match_encoding = encoding .get ('match' , '' )
242+ if not match_encoding :
243+ print (f"Warning: 'encoding.match' not found in YAML file '{ yaml_file_path } '." )
244+ return match_encoding
245+ except FileNotFoundError :
246+ print (f"Error: YAML file '{ yaml_file_path } ' not found." )
247+ return ''
248+ except yaml .YAMLError as e :
249+ print (f"Error: Failed to parse YAML file '{ yaml_file_path } ': { e } " )
250+ return ''
214251
215252def main ():
216253 """
@@ -229,13 +266,13 @@ def main():
229266 ]
230267
231268 # Define the path to the directory containing YAML files
232- yaml_directory = '../../arch/inst/V ' # Replace with your actual directory path
269+ yaml_directory = '../../arch/inst/' # Replace with your actual directory path
233270
234- # Get instruction names from the YAML directory
235- yaml_instr_names = get_instruction_names_from_directory (yaml_directory )
236- if not yaml_instr_names :
237- print ("No instruction names found. Exiting." )
238- sys .exit (1 ) # Exit if no instruction names are found
271+ # Get instruction YAML mappings from the YAML directory recursively
272+ instr_yaml_map = get_instruction_yaml_files (yaml_directory )
273+ if not instr_yaml_map :
274+ print ("No YAML files found. Exiting." )
275+ sys .exit (1 ) # Exit if no YAML files are found
239276
240277 # Parse header files to get all #define constants
241278 defines = parse_header_files (header_files )
@@ -252,16 +289,33 @@ def main():
252289 # Group instructions by name
253290 instr_group = defaultdict (list )
254291 for instr in instructions :
255- if instr ['name' ] in yaml_instr_names and 'INSN_ALIAS' not in instr ['flags' ]:
292+ if instr ['name' ] in instr_yaml_map and 'INSN_ALIAS' not in instr ['flags' ]:
256293 instr_group [instr ['name' ]].append (instr )
257294
258295 if not instr_group :
259296 print ("No matching non-alias instructions found between YAML files and instruction definitions." )
260297 sys .exit (1 ) # Exit if no matching instructions are found
261298
299+ # Initialize a flag to track mismatches
300+ mismatches_found = False
301+
262302 # Process each instruction group
263303 for name , defs in instr_group .items ():
264304 success_encodings = []
305+ yaml_encoding = ''
306+ yaml_file_path = instr_yaml_map .get (name , '' )
307+
308+ if not yaml_file_path :
309+ # No YAML file found for this instruction
310+ print (f"Warning: No YAML file found for instruction '{ name } '. Skipping comparison." )
311+ continue
312+
313+ yaml_encoding = parse_yaml_encoding (yaml_file_path )
314+
315+ if not yaml_encoding :
316+ # Skip comparison if YAML encoding is missing
317+ continue
318+
265319 for d in defs :
266320 try :
267321 # Evaluate MATCH expression
@@ -279,23 +333,31 @@ def main():
279333 continue
280334
281335 if success_encodings :
282- # Print all successful encodings for this instruction
283336 for class_ , encoding in success_encodings :
284- print (f'Instruction: { name } ' )
285- print (f' Class: { class_ } ' )
286- print (f' match: { encoding } \n ' )
337+ if encoding != yaml_encoding :
338+ mismatches_found = True
339+ print (f"Error: Encoding mismatch for instruction '{ name } ' in YAML file '{ yaml_file_path } '." )
340+ print (f" YAML match : { yaml_encoding } " )
341+ print (f" Generated match: { encoding } \n " )
287342 else :
288343 # No valid definitions could be processed for this instruction
289- print (f"Error: Could not evaluate any MATCH/MASK expressions for instruction '{ name } '. Exiting. " )
290- sys . exit ( 1 ) # Terminate the script
344+ print (f"Error: Could not evaluate any MATCH/MASK expressions for instruction '{ name } ' in YAML file ' { yaml_file_path } '. \n " )
345+ mismatches_found = True
291346
292347 # Optionally, notify about YAML files without corresponding instruction definitions
293348 defined_instr_names = set (instr ['name' ] for instr in instructions )
349+ yaml_instr_names = set (instr_yaml_map .keys ())
294350 undefined_yaml_instr = yaml_instr_names - defined_instr_names
295351 if undefined_yaml_instr :
296352 print ("Warning: The following instructions from YAML directory do not have definitions:" )
297- for instr in undefined_yaml_instr :
353+ for instr in sorted ( undefined_yaml_instr ) :
298354 print (f" - { instr } " )
299355
356+ # Exit with appropriate status code
357+ if mismatches_found :
358+ sys .exit (1 ) # Exit with error code if any mismatches are found
359+ else :
360+ sys .exit (0 ) # Successful execution
361+
300362if __name__ == "__main__" :
301363 main ()
0 commit comments