Coverage for tsfpga/vivado/build_result.py: 97%

30 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-21 23:39 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the tsfpga project, a project platform for modern FPGA development. 

5# https://tsfpga.com 

6# https://github.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8 

9from __future__ import annotations 

10 

11from tsfpga.build_result import BuildResult as BaseBuildResult 

12from tsfpga.build_result import _to_engineering_string 

13 

14from .logic_level_distribution_parser import LogicLevelDistributionParser 

15 

16 

17class VivadoBuildResult(BaseBuildResult): 

18 """ 

19 The result of a Vivado build. 

20 

21 Attributes: 

22 synthesis_run_name (`str`): The name of the Vivado synthesis run that produced this 

23 result (e.g. ``synth_2``). 

24 implementation_run_name (`str`): The name of the Vivado implementation run that produced 

25 this result (e.g. ``impl_2``). Will be ``None`` for netlist (synthesis-only) builds, 

26 since those have no implementation step. 

27 implementation_size (`dict`): A dictionary with the utilization of primitives for 

28 the implemented design. 

29 Will be ``None`` if implementation failed or did not run. 

30 logic_level_distribution (str): A table with logic level distribution as reported by 

31 Vivado. Will be ``None`` for non-netlist builds. 

32 Will be ``None`` if synthesis failed or did not run. 

33 """ 

34 

35 def __init__(self, name: str, synthesis_run_name: str) -> None: 

36 """ 

37 Arguments: 

38 name: The name of the build. 

39 synthesis_run_name: The name of the Vivado run that produced this result 

40 (e.g. ``synth_2``). 

41 """ 

42 super().__init__(name=name) 

43 

44 self.synthesis_run_name = synthesis_run_name 

45 self.implementation_run_name: str | None = None 

46 

47 self.implementation_size: dict[str, int] | None = None 

48 

49 self.logic_level_distribution: str | None = None 

50 

51 self.maximum_synthesis_frequency_hz: float | None = None 

52 

53 def _get_size_to_report(self) -> tuple[str, dict[str, int]] | None: 

54 if self.implementation_size: 

55 return "implementation", self.implementation_size 

56 

57 return super()._get_size_to_report() 

58 

59 def report(self) -> str | None: 

60 """ 

61 Return a report of the build result. Includes all metrics and information that has been 

62 extracted from the Vivado reports. 

63 """ 

64 result = super().report() 

65 if result is None: 

66 return None 

67 

68 if self.maximum_synthesis_frequency_hz: 

69 result += ( 

70 f"\nMaximum synthesis frequency estimate: " 

71 f"{_to_engineering_string(value=self.maximum_synthesis_frequency_hz)}Hz" 

72 ) 

73 

74 if self.logic_level_distribution: 

75 result += f"\nLogic level distribution:\n{self.logic_level_distribution}" 

76 

77 return result 

78 

79 @property 

80 def maximum_logic_level(self) -> int | None: 

81 """ 

82 The maximum level in the the :attr:`.VivadoBuildResult.logic_level_distribution`. 

83 Will be ``None`` for non-netlist builds. 

84 Will be ``None`` if synthesis failed or did not run. 

85 

86 Return: 

87 The maximum logic level. 

88 """ 

89 if not self.logic_level_distribution: 

90 return None 

91 

92 return LogicLevelDistributionParser.get_maximum_logic_level( 

93 table=self.logic_level_distribution 

94 )