Coverage for pyEDAA/OSVVM/Tcl.py: 84%

129 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-10 07:04 +0000

1# ==================================================================================================================== # 

2# _____ ____ _ _ ___ ______ ____ ____ __ # 

3# _ __ _ _| ____| _ \ / \ / \ / _ \/ ___\ \ / /\ \ / / \/ | # 

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | | | \___ \\ \ / / \ \ / /| |\/| | # 

5# | |_) | |_| | |___| |_| / ___ \ / ___ \ | |_| |___) |\ V / \ V / | | | | # 

6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)___/|____/ \_/ \_/ |_| |_| # 

7# |_| |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2025-2025 Patrick Lehmann - Boetzingen, Germany # 

15# # 

16# Licensed under the Apache License, Version 2.0 (the "License"); # 

17# you may not use this file except in compliance with the License. # 

18# You may obtain a copy of the License at # 

19# # 

20# http://www.apache.org/licenses/LICENSE-2.0 # 

21# # 

22# Unless required by applicable law or agreed to in writing, software # 

23# distributed under the License is distributed on an "AS IS" BASIS, # 

24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

25# See the License for the specific language governing permissions and # 

26# limitations under the License. # 

27# # 

28# SPDX-License-Identifier: Apache-2.0 # 

29# ==================================================================================================================== # 

30# 

31from pathlib import Path 

32from textwrap import dedent 

33from tkinter import Tk, Tcl, TclError 

34from typing import Any, Dict, Callable, Optional as Nullable 

35 

36from pyTooling.Decorators import readonly, export 

37from pyVHDLModel import VHDLVersion 

38 

39from pyEDAA.OSVVM import OSVVMException 

40from pyEDAA.OSVVM.Environment import Context, osvvmContext 

41from pyEDAA.OSVVM.Procedures import noop 

42from pyEDAA.OSVVM.Procedures import FileExists, DirectoryExists, FindOsvvmSettingsDirectory 

43from pyEDAA.OSVVM.Procedures import build, include, library, analyze, simulate, generic 

44from pyEDAA.OSVVM.Procedures import TestSuite, TestName, RunTest 

45from pyEDAA.OSVVM.Procedures import ChangeWorkingDirectory, CreateOsvvmScriptSettingsPkg 

46from pyEDAA.OSVVM.Procedures import SetVHDLVersion, GetVHDLVersion 

47from pyEDAA.OSVVM.Procedures import SetCoverageAnalyzeEnable, SetCoverageSimulateEnable 

48 

49 

50@export 

51class TclEnvironment: 

52 _tcl: Tk 

53 _procedures: Dict[str, Callable] 

54 _context: Context 

55 

56 def __init__(self, context: Context) -> None: 

57 self._context = context 

58 context._processor = self 

59 

60 self._tcl = Tcl() 

61 self._procedures = {} 

62 

63 @readonly 

64 def TCL(self) -> Tk: 

65 return self._tcl 

66 

67 @readonly 

68 def Procedures(self) -> Dict[str, Callable]: 

69 return self._procedures 

70 

71 @readonly 

72 def Context(self) -> Context: 

73 return self._context 

74 

75 def RegisterPythonFunctionAsTclProcedure(self, pythonFunction: Callable, tclProcedureName: Nullable[str] = None): 

76 if tclProcedureName is None: 

77 tclProcedureName = pythonFunction.__name__ 

78 

79 self._tcl.createcommand(tclProcedureName, pythonFunction) 

80 self._procedures[tclProcedureName] = pythonFunction 

81 

82 def LoadProFile(self, path: Path) -> None: 

83 includeFile = self._context.IncludeFile(path) 

84 

85 self.EvaluateProFile(includeFile) 

86 

87 def EvaluateProFile(self, path: Path) -> None: 

88 try: 

89 self._tcl.evalfile(str(path)) 

90 except TclError as ex: 

91 raise getException(ex, self._context) 

92 

93 def __setitem__(self, tclVariableName: str, value: Any) -> None: 

94 self._tcl.setvar(tclVariableName, value) 

95 

96 def __getitem__(self, tclVariableName: str) -> None: 

97 return self._tcl.getvar(tclVariableName) 

98 

99 def __delitem__(self, tclVariableName: str) -> None: 

100 self._tcl.unsetvar(tclVariableName) 

101 

102 

103@export 

104class OsvvmVariables: 

105 _vhdlVersion: VHDLVersion 

106 _toolVendor: str 

107 _toolName: str 

108 _toolVersion: str 

109 

110 def __init__( 

111 self, 

112 vhdlVersion: Nullable[VHDLVersion] = None, 

113 toolVendor: Nullable[str] = None, 

114 toolName: Nullable[str] = None, 

115 toolVersion: Nullable[str] = None 

116 ) -> None: 

117 self._vhdlVersion = vhdlVersion if vhdlVersion is not None else VHDLVersion.VHDL2008 

118 self._toolVendor = toolVendor if toolVendor is not None else "EDA²" 

119 self._toolName = toolName if toolName is not None else "pyEDAA.ProjectModel" 

120 self._toolVersion = toolVersion if toolVersion is not None else "0.1" 

121 

122 @readonly 

123 def VHDlversion(self) -> VHDLVersion: 

124 return self._vhdlVersion 

125 

126 @readonly 

127 def ToolVendor(self) -> str: 

128 return self._toolVendor 

129 

130 @readonly 

131 def ToolName(self) -> str: 

132 return self._toolName 

133 

134 @readonly 

135 def ToolVersion(self) -> str: 

136 return self._toolVersion 

137 

138 

139@export 

140class OsvvmProFileProcessor(TclEnvironment): 

141 def __init__( 

142 self, 

143 context: Nullable[Context] = None, 

144 osvvmVariables: Nullable[OsvvmVariables] = None 

145 ) -> None: 

146 if context is None: 146 ↛ 149line 146 didn't jump to line 149 because the condition on line 146 was always true

147 context = osvvmContext 

148 

149 super().__init__(context) 

150 

151 if osvvmVariables is None: 151 ↛ 154line 151 didn't jump to line 154 because the condition on line 151 was always true

152 osvvmVariables = OsvvmVariables() 

153 

154 self.LoadOsvvmDefaults(osvvmVariables) 

155 self.OverwriteTclProcedures() 

156 self.RegisterTclProcedures() 

157 

158 def LoadOsvvmDefaults(self, osvvmVariables: OsvvmVariables) -> None: 

159 match osvvmVariables.VHDlversion: 

160 case VHDLVersion.VHDL2002: 160 ↛ 161line 160 didn't jump to line 161 because the pattern on line 160 never matched

161 version = "2002" 

162 case VHDLVersion.VHDL2008: 162 ↛ 164line 162 didn't jump to line 164 because the pattern on line 162 always matched

163 version = "2008" 

164 case VHDLVersion.VHDL2019: 

165 version = "2019" 

166 case _: 

167 version = "unsupported" 

168 

169 code = dedent(f"""\ 

170 namespace eval ::osvvm { 

171 variable VhdlVersion {version} 

172 variable ToolVendor "{osvvmVariables.ToolVendor}" 

173 variable ToolName "{osvvmVariables.ToolName}" 

174 variable ToolNameVersion "{osvvmVariables.ToolVersion}" 

175 variable ToolSupportsDeferredConstants 1 

176 variable ToolSupportsGenericPackages 1 

177 variable FunctionalCoverageIntegratedInSimulator "default" 

178 variable Support2019FilePath 1 

179 

180 variable ClockResetVersion 0 

181 } 

182 """) 

183 

184 try: 

185 self._tcl.eval(code) 

186 except TclError as ex: 

187 raise OSVVMException(f"TCL error occurred, when initializing OSVVM variables.") from ex 

188 

189 def OverwriteTclProcedures(self) -> None: 

190 self.RegisterPythonFunctionAsTclProcedure(noop, "puts") 

191 

192 def RegisterTclProcedures(self) -> None: 

193 self.RegisterPythonFunctionAsTclProcedure(build) 

194 self.RegisterPythonFunctionAsTclProcedure(include) 

195 self.RegisterPythonFunctionAsTclProcedure(library) 

196 self.RegisterPythonFunctionAsTclProcedure(analyze) 

197 self.RegisterPythonFunctionAsTclProcedure(simulate) 

198 self.RegisterPythonFunctionAsTclProcedure(generic) 

199 

200 self.RegisterPythonFunctionAsTclProcedure(TestSuite) 

201 self.RegisterPythonFunctionAsTclProcedure(TestName) 

202 self.RegisterPythonFunctionAsTclProcedure(RunTest) 

203 

204 self.RegisterPythonFunctionAsTclProcedure(SetVHDLVersion) 

205 self.RegisterPythonFunctionAsTclProcedure(GetVHDLVersion) 

206 self.RegisterPythonFunctionAsTclProcedure(SetCoverageAnalyzeEnable) 

207 self.RegisterPythonFunctionAsTclProcedure(SetCoverageSimulateEnable) 

208 

209 self.RegisterPythonFunctionAsTclProcedure(FileExists) 

210 self.RegisterPythonFunctionAsTclProcedure(DirectoryExists) 

211 self.RegisterPythonFunctionAsTclProcedure(ChangeWorkingDirectory) 

212 

213 self.RegisterPythonFunctionAsTclProcedure(FindOsvvmSettingsDirectory) 

214 self.RegisterPythonFunctionAsTclProcedure(CreateOsvvmScriptSettingsPkg) 

215 

216 

217@export 

218def getException(ex: Exception, context: Context) -> Exception: 

219 if str(ex) == "": 219 ↛ 223line 219 didn't jump to line 223 because the condition on line 219 was always true

220 if (lastException := context.LastException) is not None: 220 ↛ 223line 220 didn't jump to line 223 because the condition on line 220 was always true

221 return lastException 

222 

223 return ex