emayecs | 5656b2b | 2021-08-04 12:44:13 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
emayecs | 5966a53 | 2021-07-29 10:07:02 -0400 | [diff] [blame] | 2 | # |
| 3 | #----------------------------------------------------------- |
emayecs | 1474831 | 2021-08-05 14:21:26 -0400 | [diff] [blame] | 4 | # Simulation hints management for the |
emayecs | 5966a53 | 2021-07-29 10:07:02 -0400 | [diff] [blame] | 5 | # characterization tool |
| 6 | #----------------------------------------------------------- |
| 7 | # Written by Tim Edwards |
| 8 | # efabless, inc. |
| 9 | # March 21, 2017 |
| 10 | # Version 0.1 |
| 11 | #-------------------------------------------------------- |
| 12 | |
| 13 | import re |
| 14 | import tkinter |
| 15 | from tkinter import ttk |
| 16 | |
| 17 | class SimHints(tkinter.Toplevel): |
| 18 | """Characterization tool simulation hints management.""" |
| 19 | |
| 20 | def __init__(self, parent=None, fontsize = 11, *args, **kwargs): |
| 21 | '''See the __init__ for Tkinter.Toplevel.''' |
| 22 | tkinter.Toplevel.__init__(self, parent, *args, **kwargs) |
| 23 | |
| 24 | s = ttk.Style() |
| 25 | s.configure('normal.TButton', font=('Helvetica', fontsize), border = 3, relief = 'raised') |
| 26 | self.protocol("WM_DELETE_WINDOW", self.close) |
| 27 | self.parent = parent |
| 28 | self.withdraw() |
| 29 | self.title('Simulation hints management') |
| 30 | self.sframe = tkinter.Frame(self) |
| 31 | self.sframe.grid(column = 0, row = 0, sticky = "news") |
| 32 | |
| 33 | self.sframe.stitle = ttk.Label(self.sframe, |
| 34 | style='title.TLabel', text = 'Hints') |
| 35 | self.sframe.stitle.pack(side = 'top', fill = 'x', expand = 'true') |
| 36 | self.sframe.sbar = ttk.Separator(self.sframe, orient='horizontal') |
| 37 | self.sframe.sbar.pack(side = 'top', fill = 'x', expand = 'true') |
| 38 | |
| 39 | self.sframe.curparam = ttk.Label(self.sframe, |
| 40 | style='title.TLabel', text = 'None') |
| 41 | self.sframe.curparam.pack(side = 'top', fill = 'x', expand = 'true') |
| 42 | self.sframe.sbar2 = ttk.Separator(self.sframe, orient='horizontal') |
| 43 | self.sframe.sbar2.pack(side = 'top', fill = 'x', expand = 'true') |
| 44 | |
| 45 | # Keep current parameter |
| 46 | self.param = None |
| 47 | |
| 48 | #-------------------------------------------------------- |
| 49 | # reltol option |
| 50 | #-------------------------------------------------------- |
| 51 | |
| 52 | self.sframe.do_reltol = tkinter.Frame(self.sframe) |
| 53 | self.sframe.do_reltol.pack(side = 'top', anchor = 'w', fill = 'x', expand = 'true') |
| 54 | |
| 55 | self.do_reltol = tkinter.IntVar(self.sframe) |
| 56 | self.do_reltol.set(0) |
| 57 | self.sframe.do_reltol.enable = ttk.Checkbutton(self.sframe.do_reltol, |
| 58 | text='Set reltol', variable = self.do_reltol, |
| 59 | command=self.apply_reltol) |
| 60 | self.sframe.do_reltol.value = ttk.Entry(self.sframe.do_reltol) |
| 61 | self.sframe.do_reltol.value.delete(0, 'end') |
| 62 | self.sframe.do_reltol.value.insert(0, '1.0E-3') |
| 63 | # Return or leave window applies hint, if enabled |
| 64 | self.sframe.do_reltol.value.bind('<Return>', self.apply_reltol) |
| 65 | self.sframe.do_reltol.value.bind('<Leave>', self.apply_reltol) |
| 66 | self.sframe.do_reltol.enable.pack(side = 'left', anchor = 'w') |
| 67 | self.sframe.do_reltol.value.pack(side = 'left', anchor = 'w', fill='x', expand='true') |
| 68 | |
| 69 | #-------------------------------------------------------- |
| 70 | # rshunt option |
| 71 | #-------------------------------------------------------- |
| 72 | |
| 73 | self.sframe.do_rshunt = tkinter.Frame(self.sframe) |
| 74 | self.sframe.do_rshunt.pack(side = 'top', anchor = 'w', fill = 'x', expand = 'true') |
| 75 | |
| 76 | self.do_rshunt = tkinter.IntVar(self.sframe) |
| 77 | self.do_rshunt.set(0) |
| 78 | self.sframe.do_rshunt.enable = ttk.Checkbutton(self.sframe.do_rshunt, |
| 79 | text='Use shunt resistance', variable = self.do_rshunt, |
| 80 | command=self.apply_rshunt) |
| 81 | self.sframe.do_rshunt.value = ttk.Entry(self.sframe.do_rshunt) |
| 82 | self.sframe.do_rshunt.value.delete(0, 'end') |
| 83 | self.sframe.do_rshunt.value.insert(0, '1.0E20') |
| 84 | # Return or leave window applies hint, if enabled |
| 85 | self.sframe.do_rshunt.value.bind('<Return>', self.apply_rshunt) |
| 86 | self.sframe.do_rshunt.value.bind('<Leave>', self.apply_rshunt) |
| 87 | self.sframe.do_rshunt.enable.pack(side = 'left', anchor = 'w') |
| 88 | self.sframe.do_rshunt.value.pack(side = 'left', anchor = 'w', fill='x', expand='true') |
| 89 | |
| 90 | #-------------------------------------------------------- |
| 91 | # nodeset option |
| 92 | #-------------------------------------------------------- |
| 93 | |
| 94 | self.sframe.do_nodeset = tkinter.Frame(self.sframe) |
| 95 | self.sframe.do_nodeset.pack(side = 'top', anchor = 'w', fill = 'x', expand = 'true') |
| 96 | |
| 97 | self.do_nodeset = tkinter.IntVar(self.sframe) |
| 98 | self.do_nodeset.set(0) |
| 99 | self.sframe.do_nodeset.enable = ttk.Checkbutton(self.sframe.do_nodeset, |
| 100 | text='Use nodeset', variable = self.do_nodeset, |
| 101 | command=self.apply_nodeset) |
| 102 | self.sframe.do_nodeset.value = ttk.Entry(self.sframe.do_nodeset) |
| 103 | self.sframe.do_nodeset.value.delete(0, 'end') |
| 104 | # Return or leave window applies hint, if enabled |
| 105 | self.sframe.do_nodeset.value.bind('<Return>', self.apply_nodeset) |
| 106 | self.sframe.do_nodeset.value.bind('<Leave>', self.apply_nodeset) |
| 107 | self.sframe.do_nodeset.enable.pack(side = 'left', anchor = 'w') |
| 108 | self.sframe.do_nodeset.value.pack(side = 'left', anchor = 'w', fill='x', expand='true') |
| 109 | |
| 110 | #-------------------------------------------------------- |
| 111 | # itl1 option |
| 112 | #-------------------------------------------------------- |
| 113 | |
| 114 | self.sframe.do_itl1 = tkinter.Frame(self.sframe) |
| 115 | self.sframe.do_itl1.pack(side = 'top', anchor = 'w', fill = 'x', expand = 'true') |
| 116 | |
| 117 | self.do_itl1 = tkinter.IntVar(self.sframe) |
| 118 | self.do_itl1.set(0) |
| 119 | self.sframe.do_itl1.enable = ttk.Checkbutton(self.sframe.do_itl1, |
| 120 | text='Set gmin iterations', variable = self.do_itl1, |
| 121 | command=self.apply_itl1) |
| 122 | self.sframe.do_itl1.value = ttk.Entry(self.sframe.do_itl1) |
| 123 | self.sframe.do_itl1.value.delete(0, 'end') |
| 124 | self.sframe.do_itl1.value.insert(0, '100') |
| 125 | # Return or leave window applies hint, if enabled |
| 126 | self.sframe.do_itl1.value.bind('<Return>', self.apply_itl1) |
| 127 | self.sframe.do_itl1.value.bind('<Leave>', self.apply_itl1) |
| 128 | self.sframe.do_itl1.enable.pack(side = 'left', anchor = 'w') |
| 129 | self.sframe.do_itl1.value.pack(side = 'left', anchor = 'w', fill='x', expand='true') |
| 130 | |
| 131 | #-------------------------------------------------------- |
| 132 | # include option |
| 133 | # Disabled for now. This needs to limit the selection of |
| 134 | # files to include to a drop-down selection list. |
| 135 | #-------------------------------------------------------- |
| 136 | self.sframe.do_include = tkinter.Frame(self.sframe) |
| 137 | # self.sframe.do_include.pack(side = 'top', anchor = 'w', fill = 'x', expand = 'true') |
| 138 | |
| 139 | self.do_include = tkinter.IntVar(self.sframe) |
| 140 | self.do_include.set(0) |
| 141 | self.sframe.do_include.enable = ttk.Checkbutton(self.sframe.do_include, |
| 142 | text='Include netlist', variable = self.do_include, |
| 143 | command=self.apply_include) |
| 144 | self.sframe.do_include.value = ttk.Entry(self.sframe.do_include) |
| 145 | self.sframe.do_include.value.delete(0, 'end') |
| 146 | # Return or leave window applies hint, if enabled |
| 147 | self.sframe.do_include.value.bind('<Return>', self.apply_include) |
| 148 | self.sframe.do_include.value.bind('<Leave>', self.apply_include) |
| 149 | self.sframe.do_include.enable.pack(side = 'left', anchor = 'w') |
| 150 | self.sframe.do_include.value.pack(side = 'left', anchor = 'w', fill='x', expand='true') |
| 151 | |
| 152 | #-------------------------------------------------------- |
| 153 | # alternative method option |
| 154 | #-------------------------------------------------------- |
| 155 | |
| 156 | self.sframe.do_method = tkinter.Frame(self.sframe) |
| 157 | self.sframe.do_method.pack(side = 'top', anchor = 'w', fill = 'x', expand = 'true') |
| 158 | |
| 159 | self.do_method = tkinter.IntVar(self.sframe) |
| 160 | self.do_method.set(0) |
| 161 | self.sframe.do_method.enable = ttk.Checkbutton(self.sframe.do_method, |
| 162 | text='Use alternate method', variable = self.do_method, |
| 163 | command=self.apply_method) |
| 164 | self.sframe.do_method.value = ttk.Entry(self.sframe.do_method) |
| 165 | self.sframe.do_method.value.delete(0, 'end') |
| 166 | self.sframe.do_method.value.insert(0, '0') |
| 167 | # Return or leave window applies hint, if enabled |
| 168 | self.sframe.do_method.value.bind('<Return>', self.apply_method) |
| 169 | self.sframe.do_method.value.bind('<Leave>', self.apply_method) |
| 170 | self.sframe.do_method.enable.pack(side = 'left', anchor = 'w') |
| 171 | self.sframe.do_method.value.pack(side = 'left', anchor = 'w', fill='x', expand='true') |
| 172 | |
| 173 | #-------------------------------------------------------- |
| 174 | |
| 175 | self.bbar = ttk.Frame(self) |
| 176 | self.bbar.grid(column = 0, row = 1, sticky = "news") |
| 177 | |
| 178 | self.bbar.apply_button = ttk.Button(self.bbar, text='Apply', |
| 179 | command=self.apply_hints, style = 'normal.TButton') |
| 180 | self.bbar.apply_button.grid(column=0, row=0, padx = 5) |
| 181 | |
| 182 | self.bbar.close_button = ttk.Button(self.bbar, text='Close', |
| 183 | command=self.close, style = 'normal.TButton') |
| 184 | self.bbar.close_button.grid(column=1, row=0, padx = 5) |
| 185 | |
| 186 | def apply_reltol(self, value = ''): |
| 187 | # "value" is passed from binding callback but is not used |
| 188 | have_reltol = self.do_reltol.get() |
| 189 | if have_reltol: |
| 190 | if not 'hints' in self.param: |
| 191 | phints = {} |
| 192 | else: |
| 193 | phints = self.param['hints'] |
| 194 | phints['reltol'] = self.sframe.do_reltol.value.get() |
| 195 | self.param['hints'] = phints |
| 196 | else: |
| 197 | if 'hints' in self.param: |
| 198 | self.param['hints'].pop('reltol', None) |
| 199 | |
| 200 | def apply_rshunt(self, value = ''): |
| 201 | # "value" is passed from binding callback but is not used |
| 202 | have_rshunt = self.do_rshunt.get() |
| 203 | if have_rshunt: |
| 204 | if not 'hints' in self.param: |
| 205 | phints = {} |
| 206 | else: |
| 207 | phints = self.param['hints'] |
| 208 | phints['rshunt'] = self.sframe.do_rshunt.value.get() |
| 209 | self.param['hints'] = phints |
| 210 | else: |
| 211 | if 'hints' in self.param: |
| 212 | self.param['hints'].pop('rshunt', None) |
| 213 | |
| 214 | def apply_itl1(self, value = ''): |
| 215 | # "value" is passed from binding callback but is not used |
| 216 | have_itl1 = self.do_itl1.get() |
| 217 | if have_itl1: |
| 218 | if not 'hints' in self.param: |
| 219 | phints = {} |
| 220 | else: |
| 221 | phints = self.param['hints'] |
| 222 | phints['itl1'] = self.sframe.do_itl1.value.get() |
| 223 | self.param['hints'] = phints |
| 224 | else: |
| 225 | if 'hints' in self.param: |
| 226 | self.param['hints'].pop('itl1', None) |
| 227 | |
| 228 | |
| 229 | def apply_nodeset(self, value = ''): |
| 230 | # "value" is passed from binding callback but is not used |
| 231 | have_nodeset = self.do_nodeset.get() |
| 232 | if have_nodeset: |
| 233 | if not 'hints' in self.param: |
| 234 | phints = {} |
| 235 | else: |
| 236 | phints = self.param['hints'] |
| 237 | phints['nodeset'] = self.sframe.do_nodeset.value.get() |
| 238 | self.param['hints'] = phints |
| 239 | else: |
| 240 | if 'hints' in self.param: |
| 241 | self.param['hints'].pop('nodeset', None) |
| 242 | |
| 243 | def apply_include(self, value = ''): |
| 244 | # "value" is passed from binding callback but is not used |
| 245 | have_include = self.do_include.get() |
| 246 | if have_include: |
| 247 | if not 'hints' in self.param: |
| 248 | phints = {} |
| 249 | else: |
| 250 | phints = self.param['hints'] |
| 251 | phints['include'] = self.sframe.do_include.value.get() |
| 252 | self.param['hints'] = phints |
| 253 | else: |
| 254 | if 'hints' in self.param: |
| 255 | self.param['hints'].pop('include', None) |
| 256 | |
| 257 | def apply_method(self, value = ''): |
| 258 | # "value" is passed from binding callback but is not used |
| 259 | have_method = self.do_method.get() |
| 260 | if have_method: |
| 261 | if not 'hints' in self.param: |
| 262 | phints = {} |
| 263 | else: |
| 264 | phints = self.param['hints'] |
| 265 | phints['method'] = self.sframe.do_method.value.get() |
| 266 | self.param['hints'] = phints |
| 267 | else: |
| 268 | if 'hints' in self.param: |
| 269 | self.param['hints'].pop('method', None) |
| 270 | |
| 271 | def apply_hints(self, value = ''): |
| 272 | self.apply_reltol(value) |
| 273 | self.apply_rshunt(value) |
| 274 | self.apply_itl1(value) |
| 275 | self.apply_nodeset(value) |
| 276 | self.apply_include(value) |
| 277 | self.apply_method(value) |
| 278 | |
| 279 | # Update 'Simulate' button in characterization tool with a mark |
| 280 | # indicating hints are present. Also remove the hints record |
| 281 | # from the parameter dictionary if it is empty. |
| 282 | if 'method' in self.param: |
| 283 | if 'hints' in self.param: |
| 284 | if self.param['hints'] == {}: |
| 285 | self.param.pop('hints', None) |
| 286 | simtext = 'Simulate' |
| 287 | else: |
| 288 | simtext = '\u2022Simulate' |
| 289 | else: |
| 290 | simtext = 'Simulate' |
| 291 | self.simbutton.config(text=simtext) |
| 292 | |
| 293 | def grid_configure(self, padx, pady): |
| 294 | pass |
| 295 | |
| 296 | def redisplay(self): |
| 297 | pass |
| 298 | |
| 299 | def populate(self, param, simbutton = False): |
| 300 | if 'display' in param: |
| 301 | self.sframe.curparam.config(text=param['display']) |
| 302 | else: |
| 303 | self.sframe.curparam.config(text=param['method']) |
| 304 | |
| 305 | # Set the current parameter |
| 306 | self.param = param |
| 307 | |
| 308 | # Remember the simulate button so we can mark or unmark hints |
| 309 | self.simbutton = simbutton |
| 310 | |
| 311 | # Regenerate view and update for the indicated param. |
| 312 | if 'hints' in param: |
| 313 | phints = param['hints'] |
| 314 | if 'reltol' in phints: |
| 315 | # (1) Reltol adjustment |
| 316 | self.do_reltol.set(1) |
| 317 | self.sframe.do_reltol.value.delete(0, 'end') |
| 318 | self.sframe.do_reltol.value.insert(0, phints['reltol']) |
| 319 | else: |
| 320 | self.do_reltol.set(0) |
| 321 | if 'rshunt' in phints: |
| 322 | # (2) Gshunt option |
| 323 | self.do_rshunt.set(1) |
| 324 | self.sframe.do_rshunt.value.delete(0, 'end') |
| 325 | self.sframe.do_rshunt.value.insert(0, phints['rshunt']) |
| 326 | else: |
| 327 | self.do_rshunt.set(0) |
| 328 | if 'nodeset' in phints: |
| 329 | # (3) Nodeset |
| 330 | self.do_nodeset.set(1) |
| 331 | self.sframe.do_nodeset.value.delete(0, 'end') |
| 332 | self.sframe.do_nodeset.value.insert(0, phints['nodeset']) |
| 333 | else: |
| 334 | self.do_nodeset.set(0) |
| 335 | if 'itl1' in phints: |
| 336 | # (4) Gmin iterations (ITL1) |
| 337 | self.do_itl1.set(1) |
| 338 | self.sframe.do_itl1.value.delete(0, 'end') |
| 339 | self.sframe.do_itl1.value.insert(0, phints['itl1']) |
| 340 | else: |
| 341 | self.do_itl1.set(0) |
| 342 | if 'include' in phints: |
| 343 | # (5) Include library (from dropdown list) |
| 344 | self.do_include.set(1) |
| 345 | self.sframe.do_include.value.delete(0, 'end') |
| 346 | self.sframe.do_include.value.insert(0, phints['include']) |
| 347 | else: |
| 348 | self.do_include.set(0) |
| 349 | if 'method' in phints: |
| 350 | # (6) Alternative method (where indicated) |
| 351 | self.do_method.set(1) |
| 352 | self.sframe.do_method.value.delete(0, 'end') |
| 353 | self.sframe.do_method.value.insert(0, phints['method']) |
| 354 | else: |
| 355 | self.do_method.set(0) |
| 356 | else: |
| 357 | # No hints, so set everything to unchecked |
| 358 | self.do_reltol.set(0) |
| 359 | self.do_rshunt.set(0) |
| 360 | self.do_nodeset.set(0) |
| 361 | self.do_itl1.set(0) |
| 362 | self.do_include.set(0) |
| 363 | self.do_method.set(0) |
| 364 | |
| 365 | def close(self): |
| 366 | # pop down settings window |
| 367 | self.withdraw() |
| 368 | |
| 369 | def open(self): |
| 370 | # pop up settings window |
| 371 | self.deiconify() |
| 372 | self.lift() |