Ejemplo n.º 1
0
def test_no_reports(tmp_path):

    from edalize.reporting import Reporting

    rpt = Reporting.report(str(tmp_path))

    assert rpt == {"summary": None, "resources": None, "timing": None}
Ejemplo n.º 2
0
def test_missing_reports(tmp_path):

    from edalize.reporting import Reporting

    (tmp_path / "top1_resource_report.txt").touch()

    rpt = Reporting.report(str(tmp_path))

    assert rpt == {"summary": None, "resources": None, "timing": None}
Ejemplo n.º 3
0
def test_missing_dir():

    from edalize.reporting import Reporting

    data_dir = Path(tests_dir + "/test_reporting/data/doesntexist")

    rpt = Reporting.report(str(data_dir))

    assert rpt == {"summary": None, "resources": None, "timing": None}
Ejemplo n.º 4
0
    def report_summary(resources: Dict[str, pd.DataFrame], timing: Dict[str,
                                                                        Any]):

        util = resources["Utilization by Hierarchy"]

        # Find a column beginning with DSP since we don't know if it's
        # DSP48A1, DSP48E2, etc.
        dsp_col = [c for c in util.columns if c.startswith("DSP")]

        if len(dsp_col) != 1:
            logger.error("Expected 1 column named DSP but found", len(dsp_col))

        resource_buckets = {
            "lut": "LUTs",
            "reg": "Slice Reg",
            "blkmem": "BRAM/FIFO",
            "dsp": dsp_col[0],
        }

        # The basic resource data is ints, but the timing information is more
        # complex
        summary = {}  # type: Dict[str, Any]

        # Resources in this table are of the form 123/456 and we want the
        # second (total) number
        for k in resource_buckets.keys():
            cell = util.iloc[0].at[resource_buckets[k]]
            summary[k] = int(str(cell).split("/")[1])

        summary["constraint"] = {}
        summary["fmax"] = {}

        # Report the constraint and Fmax value for each timegroup
        for k, v in timing["constraint"].items():
            summary["constraint"][k] = v["constraint"]
            summary["fmax"][k] = Reporting.period_to_freq(v.get("min period"))

        return summary
Ejemplo n.º 5
0
def test_period_to_freq():

    from edalize.reporting import Reporting

    assert Reporting.period_to_freq(10.0) == 100
    assert round(Reporting.period_to_freq(125, "ps", "GHZ")) == 8
    assert Reporting.period_to_freq(None) is None
    assert Reporting.period_to_freq(float("nan")) is None
    assert round(Reporting.period_to_freq("9", "ns"), 4) == round(1 / 9e-3, 4)

    with pytest.raises(ValueError):
        Reporting.period_to_freq(5, "MHz")
        Reporting.period_to_freq("invalid")
        Reporting.period_to_freq(5, "ps", "ns")
Ejemplo n.º 6
0
    def report_summary(
        resources: Dict[str, pd.DataFrame], timing: Dict[str, pd.DataFrame]
    ) -> Dict[str, Union[int, float, Dict[str, Optional[float]]]]:

        summary = {
        }  # type: Dict[str, Union[int, float, Dict[str, Optional[float]]]]

        # Vivado uses different tables and row values for different families.
        # This at least works with the Artix 7 and Kintex Ultrascale+

        if "Slice Logic" in resources:
            table = "Slice Logic"
            lut = "Slice LUTs"
            reg = "Slice Registers"
        elif "CLB Logic" in resources:
            table = "CLB Logic"
            lut = "CLB LUTs"
            reg = "CLB Registers"
        else:
            logger.error("Can't find a table with LUT information")
            return summary

        df = resources[table].set_index("Site Type")
        summary["lut"] = df.loc[lut, "Used"].item()
        summary["reg"] = df.loc[reg, "Used"].item()

        if "Memory" in resources:
            table = "Memory"
        elif "BLOCKRAM" in resources:
            table = "BLOCKRAM"
        else:
            logger.error("Can't find a table with memory information")
            return summary

        df = resources[table].set_index("Site Type")
        summary["blkmem"] = df.loc["Block RAM Tile", "Used"].item()

        if "DSP" in resources:
            table = "DSP"
        elif "ARITHMETIC" in resources:
            table = "ARITHMETIC"
        else:
            logger.error("Can't find a table with memory information")
            return summary

        df = resources[table].set_index("Site Type")
        summary["dsp"] = df.loc["DSPs", "Used"].item()

        # Return a dict indexed by the clock name
        df = timing["Clock Summary"].set_index("Clock")

        summary["constraint"] = df["Frequency(MHz)"].to_dict()

        # Loadless clocks won't have a WNS entry which maps to NaN. This will
        # be mapped to None by period_to_df which feels more appropriate.
        # Pandas.Series.transform or apply feel like the most appropriate
        # functions to use, but seem to interpret the returned None as a
        # no-op, so the mapping is done when the returned dictionary is
        # created.
        period = timing["Clock Summary"].set_index("Clock")["Period(ns)"]
        wns = timing["Intra Clock Table"].set_index("Clock")["WNS(ns)"]

        summary["fmax"] = {
            k: Reporting.period_to_freq(v)
            for k, v in (period - wns).to_dict().items()
        }

        return summary