33import yaml
44import logging
55import pprint
6+ import json
67
78pp = pprint .PrettyPrinter (indent = 2 )
89logging .basicConfig (level = logging .INFO , format = "%(levelname)s:: %(message)s" )
@@ -276,14 +277,15 @@ def load_instructions(
276277
277278 # Process RV64 encoding
278279 rv64_match = rv64_encoding .get ("match" )
280+ rv32_match = rv32_encoding .get ("match" )
281+
279282 if rv64_match :
280283 instr_dict [name ] = {
281284 "match" : rv64_match
282285 } # RV64 gets the default name
283286
284- # Process RV32 encoding with a _rv32 suffix
285- rv32_match = rv32_encoding .get ("match" )
286- if rv32_match :
287+ if rv32_match and rv32_match != rv64_match :
288+ # Process RV32 encoding with a _rv32 suffix
287289 instr_dict [f"{ name } _rv32" ] = {"match" : rv32_match }
288290
289291 continue # Skip the rest of the loop as we've already added the encodings
@@ -441,11 +443,7 @@ def load_csrs(csr_root, enabled_extensions, include_all=False, target_arch="RV64
441443 else :
442444 addr_int = int (addr_to_use , 0 )
443445
444- # For BOTH architecture, add suffix to RV32-specific CSRs
445- if target_arch == "BOTH" and base == 32 :
446- csrs [addr_int ] = f"{ name .upper ()} .RV32"
447- else :
448- csrs [addr_int ] = name .upper ()
446+ csrs [addr_int ] = name .upper ()
449447 except Exception as e :
450448 logging .error (f"Error parsing address { addr_to_use } in { path } : { e } " )
451449 address_errors += 1
@@ -468,6 +466,124 @@ def load_csrs(csr_root, enabled_extensions, include_all=False, target_arch="RV64
468466 return csrs
469467
470468
469+ def load_exception_codes (
470+ ext_dir , enabled_extensions = None , include_all = False , resolved_codes_file = None
471+ ):
472+ """Load exception codes from extension YAML files or pre-resolved JSON file."""
473+ exception_codes = []
474+ found_extensions = 0
475+ found_files = 0
476+
477+ if enabled_extensions is None :
478+ enabled_extensions = []
479+ # If we have a resolved codes file, use it instead of processing YAML files
480+ if resolved_codes_file and os .path .exists (resolved_codes_file ):
481+ try :
482+ with open (resolved_codes_file , encoding = "utf-8" ) as f :
483+ resolved_codes = json .load (f )
484+
485+ for code in resolved_codes :
486+ num = code .get ("num" )
487+ name = code .get ("name" )
488+ if num is not None and name is not None :
489+ sanitized_name = (
490+ name .lower ()
491+ .replace (" " , "_" )
492+ .replace ("/" , "_" )
493+ .replace ("-" , "_" )
494+ )
495+ exception_codes .append ((num , sanitized_name ))
496+
497+ logging .info (
498+ f"Loaded { len (exception_codes )} pre-resolved exception codes from { resolved_codes_file } "
499+ )
500+
501+ # Sort by exception code number and deduplicate
502+ seen_nums = set ()
503+ unique_codes = []
504+ for num , name in sorted (exception_codes , key = lambda x : x [0 ]):
505+ if num not in seen_nums :
506+ seen_nums .add (num )
507+ unique_codes .append ((num , name ))
508+
509+ return unique_codes
510+
511+ except Exception as e :
512+ logging .error (
513+ f"Error loading resolved codes file { resolved_codes_file } : { e } "
514+ )
515+ # Fall back to processing YAML files
516+
517+ for dirpath , _ , filenames in os .walk (ext_dir ):
518+ for fname in filenames :
519+ if not fname .endswith (".yaml" ):
520+ continue
521+
522+ found_files += 1
523+ path = os .path .join (dirpath , fname )
524+
525+ try :
526+ with open (path , encoding = "utf-8" ) as f :
527+ data = yaml .safe_load (f )
528+
529+ if not isinstance (data , dict ) or data .get ("kind" ) != "extension" :
530+ continue
531+
532+ found_extensions += 1
533+ ext_name = data .get ("name" , "unnamed" )
534+
535+ # Skip extension filtering if include_all is True
536+ if not include_all :
537+ # Filter by extension requirements
538+ definedBy = data .get ("definedBy" )
539+ if definedBy :
540+ meets_req = parse_extension_requirements (definedBy )
541+ if not meets_req (enabled_extensions ):
542+ continue
543+
544+ # Check if excluded
545+ excludedBy = data .get ("excludedBy" )
546+ if excludedBy :
547+ exclusion_check = parse_extension_requirements (excludedBy )
548+ if exclusion_check (enabled_extensions ):
549+ continue
550+
551+ # Get exception codes
552+ for code in data .get ("exception_codes" , []):
553+ num = code .get ("num" )
554+ name = code .get ("name" )
555+
556+ if num is not None and name is not None :
557+ sanitized_name = (
558+ name .lower ()
559+ .replace (" " , "_" )
560+ .replace ("/" , "_" )
561+ .replace ("-" , "_" )
562+ )
563+ exception_codes .append ((num , sanitized_name ))
564+
565+ except Exception as e :
566+ logging .error (f"Error processing file { path } : { e } " )
567+
568+ if found_extensions > 0 :
569+ logging .info (
570+ f"Found { found_extensions } extension definitions in { found_files } files"
571+ )
572+ logging .info (f"Added { len (exception_codes )} exception codes to the output" )
573+ else :
574+ logging .warning (f"No extension definitions found in { ext_dir } " )
575+
576+ # Sort by exception code number and deduplicate
577+ seen_nums = set ()
578+ unique_codes = []
579+ for num , name in sorted (exception_codes , key = lambda x : x [0 ]):
580+ if num not in seen_nums :
581+ seen_nums .add (num )
582+ unique_codes .append ((num , name ))
583+
584+ return unique_codes
585+
586+
471587def parse_match (match_str ):
472588 """
473589 Convert the bit pattern string to an integer.
0 commit comments