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" )
@@ -326,14 +327,15 @@ def load_instructions(
326327
327328 # Process RV64 encoding
328329 rv64_match = rv64_encoding .get ("match" )
330+ rv32_match = rv32_encoding .get ("match" )
331+
329332 if rv64_match :
330333 instr_dict [name ] = {
331334 "match" : rv64_match
332335 } # RV64 gets the default name
333336
334- # Process RV32 encoding with a _rv32 suffix
335- rv32_match = rv32_encoding .get ("match" )
336- if rv32_match :
337+ if rv32_match and rv32_match != rv64_match :
338+ # Process RV32 encoding with a _rv32 suffix
337339 instr_dict [f"{ name } _rv32" ] = {"match" : rv32_match }
338340
339341 continue # Skip the rest of the loop as we've already added the encodings
@@ -491,11 +493,7 @@ def load_csrs(csr_root, enabled_extensions, include_all=False, target_arch="RV64
491493 else :
492494 addr_int = int (addr_to_use , 0 )
493495
494- # For BOTH architecture, add suffix to RV32-specific CSRs
495- if target_arch == "BOTH" and base == 32 :
496- csrs [addr_int ] = f"{ name .upper ()} .RV32"
497- else :
498- csrs [addr_int ] = name .upper ()
496+ csrs [addr_int ] = name .upper ()
499497 except Exception as e :
500498 logging .error (f"Error parsing address { addr_to_use } in { path } : { e } " )
501499 address_errors += 1
@@ -518,6 +516,124 @@ def load_csrs(csr_root, enabled_extensions, include_all=False, target_arch="RV64
518516 return csrs
519517
520518
519+ def load_exception_codes (
520+ ext_dir , enabled_extensions = None , include_all = False , resolved_codes_file = None
521+ ):
522+ """Load exception codes from extension YAML files or pre-resolved JSON file."""
523+ exception_codes = []
524+ found_extensions = 0
525+ found_files = 0
526+
527+ if enabled_extensions is None :
528+ enabled_extensions = []
529+ # If we have a resolved codes file, use it instead of processing YAML files
530+ if resolved_codes_file and os .path .exists (resolved_codes_file ):
531+ try :
532+ with open (resolved_codes_file , encoding = "utf-8" ) as f :
533+ resolved_codes = json .load (f )
534+
535+ for code in resolved_codes :
536+ num = code .get ("num" )
537+ name = code .get ("name" )
538+ if num is not None and name is not None :
539+ sanitized_name = (
540+ name .lower ()
541+ .replace (" " , "_" )
542+ .replace ("/" , "_" )
543+ .replace ("-" , "_" )
544+ )
545+ exception_codes .append ((num , sanitized_name ))
546+
547+ logging .info (
548+ f"Loaded { len (exception_codes )} pre-resolved exception codes from { resolved_codes_file } "
549+ )
550+
551+ # Sort by exception code number and deduplicate
552+ seen_nums = set ()
553+ unique_codes = []
554+ for num , name in sorted (exception_codes , key = lambda x : x [0 ]):
555+ if num not in seen_nums :
556+ seen_nums .add (num )
557+ unique_codes .append ((num , name ))
558+
559+ return unique_codes
560+
561+ except Exception as e :
562+ logging .error (
563+ f"Error loading resolved codes file { resolved_codes_file } : { e } "
564+ )
565+ # Fall back to processing YAML files
566+
567+ for dirpath , _ , filenames in os .walk (ext_dir ):
568+ for fname in filenames :
569+ if not fname .endswith (".yaml" ):
570+ continue
571+
572+ found_files += 1
573+ path = os .path .join (dirpath , fname )
574+
575+ try :
576+ with open (path , encoding = "utf-8" ) as f :
577+ data = yaml .safe_load (f )
578+
579+ if not isinstance (data , dict ) or data .get ("kind" ) != "extension" :
580+ continue
581+
582+ found_extensions += 1
583+ ext_name = data .get ("name" , "unnamed" )
584+
585+ # Skip extension filtering if include_all is True
586+ if not include_all :
587+ # Filter by extension requirements
588+ definedBy = data .get ("definedBy" )
589+ if definedBy :
590+ meets_req = parse_extension_requirements (definedBy )
591+ if not meets_req (enabled_extensions ):
592+ continue
593+
594+ # Check if excluded
595+ excludedBy = data .get ("excludedBy" )
596+ if excludedBy :
597+ exclusion_check = parse_extension_requirements (excludedBy )
598+ if exclusion_check (enabled_extensions ):
599+ continue
600+
601+ # Get exception codes
602+ for code in data .get ("exception_codes" , []):
603+ num = code .get ("num" )
604+ name = code .get ("name" )
605+
606+ if num is not None and name is not None :
607+ sanitized_name = (
608+ name .lower ()
609+ .replace (" " , "_" )
610+ .replace ("/" , "_" )
611+ .replace ("-" , "_" )
612+ )
613+ exception_codes .append ((num , sanitized_name ))
614+
615+ except Exception as e :
616+ logging .error (f"Error processing file { path } : { e } " )
617+
618+ if found_extensions > 0 :
619+ logging .info (
620+ f"Found { found_extensions } extension definitions in { found_files } files"
621+ )
622+ logging .info (f"Added { len (exception_codes )} exception codes to the output" )
623+ else :
624+ logging .warning (f"No extension definitions found in { ext_dir } " )
625+
626+ # Sort by exception code number and deduplicate
627+ seen_nums = set ()
628+ unique_codes = []
629+ for num , name in sorted (exception_codes , key = lambda x : x [0 ]):
630+ if num not in seen_nums :
631+ seen_nums .add (num )
632+ unique_codes .append ((num , name ))
633+
634+ return unique_codes
635+
636+
521637def parse_match (match_str ):
522638 """
523639 Convert the bit pattern string to an integer.
0 commit comments