Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

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

3# 

4# This file is part of the tsfpga project. 

5# https://tsfpga.com 

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

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

8 

9import hashlib 

10import json 

11 

12from tsfpga.system_utils import create_file, delete, read_file 

13from .project import VivadoIpCoreProject 

14 

15 

16class VivadoIpCores: 

17 

18 """ 

19 Handle a list of IP core sources. Has a mechanism to detect whether a regenerate of IP files 

20 is needed. 

21 """ 

22 

23 project_name = "vivado_ip_project" 

24 

25 def __init__(self, modules, output_path, part_name, vivado_project_class=VivadoIpCoreProject): 

26 """ 

27 Arguments: 

28 modules (list(:class:`Module <.BaseModule>`)): IP cores from these modules will be 

29 included. 

30 output_path (`pathlib.Path`): The Vivado project will be placed here. 

31 part_name (str): Vivado part name to be used for the project. 

32 vivado_project_class: The Vivado project class that will be used for the IP core 

33 project. Is safe to leave at default in most cases. 

34 """ 

35 self.project_directory = output_path.resolve() / self.project_name 

36 self._part_name = part_name 

37 self._hash_file = self.project_directory / "ip_files_hash.txt" 

38 

39 self._setup(modules, vivado_project_class) 

40 

41 @property 

42 def compile_order_file(self): 

43 """ 

44 `pathlib.Path`: Path to the generated compile order file. 

45 """ 

46 return self.project_directory / "compile_order.txt" 

47 

48 @property 

49 def vivado_project_file(self): 

50 """ 

51 `pathlib.Path`: Path to the Vivado project file. 

52 """ 

53 return self._vivado_project.project_file(self.project_directory) 

54 

55 def create_vivado_project(self): 

56 """ 

57 Create IP core Vivado project. 

58 """ 

59 print(f"Creating IP core project in {self.project_directory}") 

60 delete(self.project_directory) 

61 self._vivado_project.create(self.project_directory) 

62 self._save_hash() 

63 

64 def create_vivado_project_if_needed(self): 

65 """ 

66 Create IP core Vivado project if anything has changed since last time this was run. 

67 If 

68 

69 * List of TCL files that create IP cores, 

70 * and contents of these files, 

71 

72 is the same then it will not create. But if anything is added or removed from the list, 

73 or the contents of a TCL file is changed, there will be a recreation. 

74 

75 Return: 

76 True if Vivado project was created. False otherwise. 

77 """ 

78 if self._should_create(): 

79 self.create_vivado_project() 

80 return True 

81 

82 return False 

83 

84 def _setup(self, modules, vivado_project_class): 

85 self._vivado_project = vivado_project_class( 

86 name=self.project_name, modules=modules, part=self._part_name 

87 ) 

88 

89 ip_core_files = [] 

90 for module in modules: 

91 # Send the same two arguments that are sent in the VivadoProject create flow 

92 ip_core_files += module.get_ip_core_files(generics=dict(), part=self._part_name) 

93 

94 self._hash = self._calculate_hash(ip_core_files) 

95 

96 @staticmethod 

97 def _calculate_hash(ip_core_files): 

98 """ 

99 A string with hashes of the different IP core files. 

100 """ 

101 data = "" 

102 

103 def sort_by_file_name(ip_core_file): 

104 return ip_core_file.path.name 

105 

106 for ip_core_file in sorted(ip_core_files, key=sort_by_file_name): 

107 data += f"{ip_core_file.path}\n" 

108 

109 if ip_core_file.variables: 

110 data += json.dumps(ip_core_file.variables, sort_keys=True) 

111 data += "\n" 

112 

113 with open(ip_core_file.path, "rb") as file_handle: 

114 ip_hash = hashlib.md5() 

115 ip_hash.update(file_handle.read()) 

116 data += f"{ip_hash.hexdigest()}\n" 

117 

118 return data 

119 

120 def _save_hash(self): 

121 create_file(self._hash_file, self._hash) 

122 

123 def _should_create(self): 

124 """ 

125 Return True if a Vivado project create is needed, i.e. if anything has changed. 

126 """ 

127 if not (self._hash_file.exists() and self.compile_order_file.exists()): 

128 return True 

129 

130 return read_file(self._hash_file) != self._hash