feat: fixes and configuration to path
This commit is contained in:
@@ -3,6 +3,10 @@ import subprocess
|
||||
import os
|
||||
import re
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
# If your environment variable isn't set, this default path will be used.
|
||||
DEFAULT_VIVADO_PATH = "/tools/Xilinx/Vivado/2023.1/bin"
|
||||
|
||||
def extract_module_name(verilog_code):
|
||||
"""
|
||||
Extract the module name from the Verilog code.
|
||||
@@ -62,10 +66,6 @@ def extract_primitives_section(lines):
|
||||
def parse_primitives_section(lines):
|
||||
"""
|
||||
Parses the primitives section lines to accumulate resource usage.
|
||||
Returns a dictionary with keys: LUT, FF, DSP, BRAM, IO.
|
||||
In this example:
|
||||
- For LUT: sums up any primitive whose name starts with "LUT" (e.g., LUT2, LUT3, ...)
|
||||
- For IO: sums the usage of IBUF and OBUF.
|
||||
"""
|
||||
resources = {"LUT": 0, "FF": 0, "DSP": 0, "BRAM": 0, "IO": 0}
|
||||
for line in lines:
|
||||
@@ -85,110 +85,140 @@ def parse_primitives_section(lines):
|
||||
resources["LUT"] += used
|
||||
if ref_name in ("IBUF", "OBUF"):
|
||||
resources["IO"] += used
|
||||
# (Add additional processing for FF, DSP, BRAM if necessary.)
|
||||
return resources
|
||||
|
||||
def run_synthesis(solution_code):
|
||||
"""
|
||||
Writes the given Verilog solution to a temporary file,
|
||||
creates a Tcl script for Vivado to run synthesis and generate a utilization report,
|
||||
runs Vivado in batch mode, and parses the resource usage report.
|
||||
Returns a dictionary with keys "optimized" and "primitives" containing resource usage.
|
||||
Runs Vivado synthesis on the provided code.
|
||||
"""
|
||||
# Write the Verilog code to a temporary file.
|
||||
# 1. Write the Verilog code to a temporary file.
|
||||
verilog_file = "temp.v"
|
||||
with open(verilog_file, "w") as f:
|
||||
f.write(solution_code)
|
||||
|
||||
# Extract the module name from the solution code.
|
||||
# 2. Extract the module name
|
||||
top_module = extract_module_name(solution_code)
|
||||
print(top_module)
|
||||
if top_module is None:
|
||||
print("Could not extract module name; using 'temp_top' as a default.")
|
||||
top_module = "temp_top"
|
||||
|
||||
vivado_project = "temp_project"
|
||||
tcl_script = "synthesis_script.tcl"
|
||||
|
||||
# Get the Vivado installation path from the environment variable.
|
||||
# 3. Resolve Vivado Path (Linux Fix)
|
||||
vivado_path_env = os.environ.get("vivado")
|
||||
if vivado_path_env is None:
|
||||
print("Error: 'vivado' environment variable is not set.")
|
||||
return None
|
||||
vivado_path = os.path.join(vivado_path_env, "vivado.bat")
|
||||
|
||||
# If env var is missing, try the default path, or search system path
|
||||
if vivado_path_env:
|
||||
vivado_bin = os.path.join(vivado_path_env, "vivado") # NO .bat
|
||||
elif os.path.exists(os.path.join(DEFAULT_VIVADO_PATH, "vivado")):
|
||||
vivado_bin = os.path.join(DEFAULT_VIVADO_PATH, "vivado")
|
||||
else:
|
||||
# Last resort: assume it's in the system PATH
|
||||
vivado_bin = "vivado"
|
||||
|
||||
# Create the Vivado Tcl script.
|
||||
tcl_script = "synthesis_script.tcl"
|
||||
vivado_project = "temp_project"
|
||||
|
||||
# 4. Create the Vivado Tcl script.
|
||||
tcl_commands = f"""
|
||||
create_project {vivado_project} -force -part xc7z020clg400-1
|
||||
add_files {verilog_file}
|
||||
set_property top {top_module} [current_fileset]
|
||||
|
||||
# Run synthesis only (no simulation)
|
||||
synth_design -top {top_module}
|
||||
synth_design -top {top_module} -part xc7z020clg400-1
|
||||
|
||||
# Generate resource utilization report
|
||||
report_utilization -file resource_usage.rpt
|
||||
|
||||
quit
|
||||
exit
|
||||
"""
|
||||
with open(tcl_script, "w") as file:
|
||||
file.write(tcl_commands)
|
||||
|
||||
# Run Vivado in batch mode using the generated Tcl script.
|
||||
# 5. Run Vivado
|
||||
print(f"Starting Synthesis for {top_module} using {vivado_bin}...")
|
||||
try:
|
||||
# Added stdout=PIPE so we can see the output if it crashes
|
||||
result = subprocess.run(
|
||||
[vivado_path, "-mode", "batch", "-source", tcl_script],
|
||||
[vivado_bin, "-mode", "batch", "-source", tcl_script],
|
||||
capture_output=True, text=True, check=True
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("Synthesis failed:", e)
|
||||
print(f"❌ Synthesis CRASHED for {top_module}")
|
||||
print("--- Error Log ---")
|
||||
print(e.stderr) # Print the actual error from Vivado
|
||||
print("-----------------")
|
||||
return None
|
||||
print(result.stdout)
|
||||
# Check for the success message in the output.
|
||||
except FileNotFoundError:
|
||||
print(f"❌ CRITICAL ERROR: Could not find Vivado executable at: {vivado_bin}")
|
||||
return None
|
||||
|
||||
# 6. Check results
|
||||
if "Finished Writing Synthesis Report" in result.stdout:
|
||||
# Read the resource utilization report.
|
||||
with open("resource_usage.rpt", "r") as f:
|
||||
report_lines = f.readlines()
|
||||
optimized_resources = parse_optimized(report_lines)
|
||||
primitives_section = extract_primitives_section(report_lines)
|
||||
primitives_resources = (parse_primitives_section(primitives_section)
|
||||
if primitives_section else {})
|
||||
return {"optimized": optimized_resources, "primitives": primitives_resources}
|
||||
print(f"✅ Synthesis Success: {top_module}")
|
||||
if os.path.exists("resource_usage.rpt"):
|
||||
with open("resource_usage.rpt", "r") as f:
|
||||
report_lines = f.readlines()
|
||||
optimized = parse_optimized(report_lines)
|
||||
primitives_sec = extract_primitives_section(report_lines)
|
||||
primitives = parse_primitives_section(primitives_sec) if primitives_sec else {}
|
||||
return {"optimized": optimized, "primitives": primitives}
|
||||
else:
|
||||
print("⚠️ Report file missing despite success message.")
|
||||
return None
|
||||
else:
|
||||
print("Synthesis did not complete successfully.")
|
||||
print(f"❌ Synthesis Failed (Logic Error) for {top_module}")
|
||||
# Print the last 10 lines of the log to help debug
|
||||
print("\n".join(result.stdout.splitlines()[-10:]))
|
||||
return None
|
||||
|
||||
def run_resource_usage():
|
||||
# Load the original JSON.
|
||||
input_json_file = "solutions.json" # Update this file name if needed.
|
||||
input_json_file = "solutions.json"
|
||||
|
||||
if not os.path.exists(input_json_file):
|
||||
print(f"Error: {input_json_file} not found.")
|
||||
return
|
||||
|
||||
with open(input_json_file, "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Traverse all top-level keys (e.g., "4o") and all subcategories.
|
||||
for top_key, top_value in data.items():
|
||||
# print(top_value.keys())
|
||||
# exit()
|
||||
# top_value should be a dict with categories (e.g., "Combinational Logic", "Finite State Machines", etc.)
|
||||
for category, module_list in top_value.items():
|
||||
# if category == "Combinational Logic":
|
||||
# continue
|
||||
print(f"Loaded {input_json_file}. Scanning for passing solutions...")
|
||||
found_any = False
|
||||
|
||||
for top_key, top_value in data.items(): # e.g. "gpt-4"
|
||||
for category, module_list in top_value.items(): # e.g. "Combinational Logic"
|
||||
for module in module_list:
|
||||
for sol in module["solutions"]:
|
||||
if sol.get("pass", "").strip().lower() == "true":
|
||||
for idx, sol in enumerate(module["solutions"]):
|
||||
|
||||
# DEBUG PRINT: Show us the status
|
||||
status = sol.get("pass", "MISSING").strip().lower()
|
||||
|
||||
if status == "true":
|
||||
found_any = True
|
||||
print(f"🚀 MATCH: Synthesizing {module['module']} (Sol #{idx})...")
|
||||
|
||||
solution_code = sol["solution"]
|
||||
print(f"Running synthesis for module '{module['module']}' in category '{category}'")
|
||||
resource_usage = run_synthesis(solution_code)
|
||||
|
||||
if resource_usage:
|
||||
sol["resource usage"] = resource_usage
|
||||
print(f" ✅ Result: {resource_usage['optimized']['LUT']} LUTs")
|
||||
else:
|
||||
sol["resource usage"] = {"optimized": {}, "primitives": {}}
|
||||
print(f" ❌ Synthesis Failed internally.")
|
||||
|
||||
# Save immediately
|
||||
with open("solutions.json", "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
else:
|
||||
sol["resource usage"] = {"optimized": {}, "primitives": {}}
|
||||
|
||||
# Write the updated JSON (with resource usage added) to a new file.
|
||||
output_json_file = "solutions.json"
|
||||
with open(output_json_file, "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
print(f"Updated JSON written to {output_json_file}")
|
||||
# Tell the user we are skipping
|
||||
print(f"⏭️ Skipping {module['module']} (Status: '{status}')")
|
||||
|
||||
if not found_any:
|
||||
print("\n⚠️ WARNING: No passing solutions found! Synthesis only runs on code that passed simulation.")
|
||||
print("To force a test, edit 'solutions.json' and change one 'pass' value to 'true'.")
|
||||
else:
|
||||
print("\n✅ All Resource Usage checks completed.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_resource_usage()
|
||||
Reference in New Issue
Block a user