Coverage for tsfpga/constraint.py: 95%

19 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-06 20:51 +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 

9# Standard libraries 

10from pathlib import Path 

11from typing import TYPE_CHECKING 

12 

13if TYPE_CHECKING: 

14 # Standard libraries 

15 

16 # Local folder libraries 

17 from .hdl_file import HdlFile 

18 

19 

20class Constraint: 

21 """ 

22 Class for handling a constraint file. 

23 

24 Can handle the regular global constraint files as well as scoped constraints. 

25 For the latter to work the constraint file name must be the same as the .vhd file name, 

26 which must be the same as the entity name. 

27 """ 

28 

29 def __init__( 

30 self, 

31 file: Path, 

32 used_in: str = "all", 

33 scoped_constraint: bool = False, 

34 processing_order: str = "normal", 

35 ) -> None: 

36 """ 

37 Arguments: 

38 file: Path to the constraint file. Typically ends in .xdc or .tcl. 

39 used_in: Optionally the constraint can be enabled only for "synth" or "impl". 

40 scoped_constraint: If enabled the constraint file will be loaded with the "-ref" 

41 argument in Vivado. An entity with the same name must exist. 

42 processing_order: Optionally the processing order can be changed to "early" or "late". 

43 """ 

44 self.file = file 

45 self.used_in = used_in 

46 self.ref = file.stem if scoped_constraint else None 

47 self.processing_order = processing_order.lower() 

48 

49 assert self.used_in in ["all", "synth", "impl"], self.used_in 

50 assert self.processing_order in ["early", "normal", "late"], self.processing_order 

51 

52 def validate_scoped_entity(self, source_files: list["HdlFile"]) -> bool: 

53 """ 

54 Make sure that a matching entity file exists in case this is a scoped constraint. 

55 The list of source files should be the synthesis files for the module that this 

56 constraint belongs to. 

57 """ 

58 if self.ref is not None: 

59 if not any([source_file.path.stem == self.ref] for source_file in source_files): 

60 raise FileNotFoundError( 

61 f"Could not find a matching entity file for scoped constraint file {self.file}" 

62 ) 

63 return True 

64 

65 def __str__(self) -> str: 

66 return str(self.file)