#! /usr/bin/env python3 # # This script pretty-prints timing/utilization reports produced by nextpnr. # You can use it in your build process like this: # # nextpnr-ecp5 ... --report report.json # ./print-report.py < report.json # # License: CC0 <https://creativecommons.org/publicdomain/zero/1.0> import json, sys from typing import Any, Dict RED, GREEN, CYAN = "\x1b[31m", "\x1b[32m", "\x1b[36m" BOLD, RESET = "\x1b[1m", "\x1b[0m" def print_header(title: str) -> None: print(BOLD + GREEN + f"==== {title} ".ljust(60, "=") + RESET) def print_frequency_report(frequencies: Dict[str, Any]) -> None: if not frequencies: return frequencies = { name: (value["achieved"], value["constraint"]) for name, value in frequencies.items() } name_width = max(len(name) for name in frequencies.keys()) print_header("Frequency Report") for name, (achieved, constraint) in frequencies.items(): name_text = CYAN + (name + ":").ljust(name_width + 1) + RESET pass_fail_text = ( f"{GREEN}PASS{RESET}" if achieved >= constraint else f"{RED}FAIL{RESET}" ) print( f" {name_text} {achieved:5.1f} MHz" f" ({pass_fail_text} at {constraint:5.1f} MHz)" ) print() def print_device_utilization(utilization: Dict[str, Any]) -> None: utilization = { name: (value["used"], value["available"]) for name, value in utilization.items() if value["used"] > 0 } percentages = { name: f"{value[0] / value[1] * 100:5.1f}" for name, value in utilization.items() } name_width = max(len(name) for name in utilization.keys()) percent_width = max(len(percent) for percent in percentages.values()) print_header("Device Utilization") for name, (used, available) in utilization.items(): name_text = CYAN + (name + ":").ljust(name_width + 1) + RESET percent_text = f"{percentages[name].rjust(percent_width)}%" print( f" {name_text} {str(used).rjust(5)} / {str(available).rjust(5)}", f"({GREEN if used <= available else RED}{percent_text}{RESET})", ) print() def print_report(report: Dict[str, Any]) -> None: print_frequency_report(report.get("fmax")) print_device_utilization(report.get("utilization")) if __name__ == "__main__": print() print_report(json.load(sys.stdin))