siliconcompiler 0.31.0__py3-none-any.whl → 0.32.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc.py +1 -0
  3. siliconcompiler/apps/sc_install.py +19 -1
  4. siliconcompiler/apps/utils/summarize.py +1 -1
  5. siliconcompiler/core.py +33 -39
  6. siliconcompiler/flows/_common.py +10 -4
  7. siliconcompiler/{package.py → package/__init__.py} +64 -177
  8. siliconcompiler/package/git.py +84 -0
  9. siliconcompiler/package/https.py +97 -0
  10. siliconcompiler/report/dashboard/components/__init__.py +16 -6
  11. siliconcompiler/report/report.py +6 -6
  12. siliconcompiler/scheduler/__init__.py +19 -10
  13. siliconcompiler/scheduler/docker_runner.py +3 -3
  14. siliconcompiler/scheduler/run_node.py +6 -3
  15. siliconcompiler/schema/schema_obj.py +7 -11
  16. siliconcompiler/templates/tcl/manifest.tcl.j2 +1 -1
  17. siliconcompiler/tools/_common/tcl/sc_pin_constraints.tcl +3 -5
  18. siliconcompiler/tools/genfasm/genfasm.py +1 -1
  19. siliconcompiler/tools/openroad/_apr.py +15 -5
  20. siliconcompiler/tools/openroad/rdlroute.py +4 -0
  21. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +3 -3
  22. siliconcompiler/tools/openroad/scripts/common/reports.tcl +10 -0
  23. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +27 -0
  24. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -13
  25. siliconcompiler/tools/slang/__init__.py +123 -33
  26. siliconcompiler/tools/slang/elaborate.py +123 -18
  27. siliconcompiler/tools/slang/lint.py +20 -10
  28. siliconcompiler/tools/surelog/__init__.py +17 -4
  29. siliconcompiler/tools/vpr/vpr.py +86 -6
  30. siliconcompiler/toolscripts/_tools.json +4 -4
  31. siliconcompiler/units.py +10 -7
  32. siliconcompiler/use.py +5 -2
  33. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/METADATA +17 -22
  34. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/RECORD +38 -36
  35. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/WHEEL +1 -1
  36. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/entry_points.txt +4 -0
  37. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/LICENSE +0 -0
  38. {siliconcompiler-0.31.0.dist-info → siliconcompiler-0.32.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,97 @@
1
+ import requests
2
+ import shutil
3
+ import tarfile
4
+ import zipfile
5
+
6
+ import os.path
7
+
8
+ from fasteners import InterProcessLock
9
+ from io import BytesIO
10
+ from urllib.parse import urlparse
11
+
12
+ from siliconcompiler import SiliconCompilerError
13
+ from siliconcompiler.package import get_download_cache_path
14
+ from siliconcompiler.package import aquire_data_lock, release_data_lock
15
+
16
+
17
+ def get_resolver(url):
18
+ if url.scheme in ("http", "https"):
19
+ return http_resolver
20
+
21
+ return None
22
+
23
+
24
+ def http_resolver(chip, package, path, ref, url, fetch):
25
+ data_path, data_path_lock = get_download_cache_path(chip, package, ref)
26
+
27
+ if not fetch:
28
+ return data_path, False
29
+
30
+ # Acquire lock
31
+ data_lock = InterProcessLock(data_path_lock)
32
+ aquire_data_lock(data_path, data_lock)
33
+
34
+ if os.path.exists(data_path):
35
+ release_data_lock(data_lock)
36
+ return data_path, False
37
+
38
+ extract_from_url(chip, package, path, ref, url, data_path)
39
+
40
+ release_data_lock(data_lock)
41
+
42
+ return data_path, True
43
+
44
+
45
+ def extract_from_url(chip, package, path, ref, url, data_path):
46
+ data_url = path
47
+ headers = {}
48
+ if os.environ.get('GIT_TOKEN') or url.username:
49
+ headers['Authorization'] = f'token {os.environ.get("GIT_TOKEN") or url.username}'
50
+ if "github" in data_url:
51
+ headers['Accept'] = 'application/octet-stream'
52
+ data_url = path
53
+ if data_url.endswith('/'):
54
+ data_url = f"{data_url}{ref}.tar.gz"
55
+ chip.logger.info(f'Downloading {package} data from {data_url}')
56
+ response = requests.get(data_url, stream=True, headers=headers)
57
+ if not response.ok:
58
+ raise SiliconCompilerError(f'Failed to download {package} data source.', chip=chip)
59
+
60
+ fileobj = BytesIO(response.content)
61
+ try:
62
+ with tarfile.open(fileobj=fileobj, mode='r|gz') as tar_ref:
63
+ tar_ref.extractall(path=data_path)
64
+ except tarfile.ReadError:
65
+ fileobj.seek(0)
66
+ # Try as zip
67
+ with zipfile.ZipFile(fileobj) as zip_ref:
68
+ zip_ref.extractall(path=data_path)
69
+
70
+ if 'github' in url.netloc and len(os.listdir(data_path)) == 1:
71
+ # Github inserts one folder at the highest level of the tar file
72
+ # this compensates for this behavior
73
+ gh_url = urlparse(data_url)
74
+
75
+ repo = gh_url.path.split('/')[2]
76
+
77
+ gh_ref = gh_url.path.split('/')[-1]
78
+ if repo.endswith('.git'):
79
+ gh_ref = ref
80
+ elif gh_ref.endswith('.tar.gz'):
81
+ gh_ref = gh_ref[0:-7]
82
+ elif gh_ref.endswith('.tgz'):
83
+ gh_ref = gh_ref[0:-4]
84
+ else:
85
+ gh_ref = gh_ref.split('.')[0]
86
+
87
+ if gh_ref.startswith('v'):
88
+ gh_ref = gh_ref[1:]
89
+
90
+ github_folder = f"{repo}-{gh_ref}"
91
+
92
+ if github_folder in os.listdir(data_path):
93
+ # This moves all files one level up
94
+ git_path = os.path.join(data_path, github_folder)
95
+ for data_file in os.listdir(git_path):
96
+ shutil.move(os.path.join(git_path, data_file), data_path)
97
+ os.removedirs(git_path)
@@ -433,7 +433,7 @@ def node_file_tree_viewer(chip, step, index):
433
433
  lookup = {}
434
434
  tree_items = []
435
435
 
436
- file_metrics = report.get_metrics_source(chip, step, index)
436
+ metrics_source, file_metrics = report.get_metrics_source(chip, step, index)
437
437
  work_dir = chip.getworkdir(step=step, index=index)
438
438
 
439
439
  def make_item(file):
@@ -446,12 +446,22 @@ def node_file_tree_viewer(chip, step, index):
446
446
 
447
447
  check_file = os.path.relpath(file['value'], work_dir)
448
448
  if check_file in file_metrics:
449
- for metric in file_metrics[check_file]:
450
- if len(item.tag) < 5:
451
- item.tag.append(sac.Tag(metric, color='green'))
452
- else:
453
- item.tag.append(sac.Tag('metrics...', color='geekblue'))
449
+ metrics = set(file_metrics[check_file])
450
+ primary_source = set()
451
+ if check_file in metrics_source:
452
+ primary_source = set(metrics_source[check_file])
453
+ metrics = metrics - primary_source
454
+
455
+ for color, metric_set in (('blue', primary_source), ('green', metrics)):
456
+ if len(item.tag) >= 5:
454
457
  break
458
+
459
+ for metric in metric_set:
460
+ if len(item.tag) < 5:
461
+ item.tag.append(sac.Tag(metric, color=color))
462
+ else:
463
+ item.tag.append(sac.Tag('metrics...', color='geekblue'))
464
+ break
455
465
  item.tooltip = "metrics: " + ", ".join(file_metrics[check_file])
456
466
 
457
467
  if 'children' in file:
@@ -302,20 +302,20 @@ def get_metrics_source(chip, step, index):
302
302
  index (string) : Index of node.
303
303
  '''
304
304
  file_to_metric = {}
305
+ metric_primary_source = {}
305
306
  tool, task = get_tool_task(chip, step, index)
306
307
  if not chip.valid('tool', tool, 'task', task, 'report'):
307
- return file_to_metric
308
+ return metric_primary_source, file_to_metric
308
309
 
309
310
  metrics = chip.getkeys('tool', tool, 'task', task, 'report')
310
311
 
311
312
  for metric in metrics:
312
313
  sources = chip.get('tool', tool, 'task', task, 'report', metric, step=step, index=index)
314
+ if sources:
315
+ metric_primary_source.setdefault(sources[0], []).append(metric)
313
316
  for source in sources:
314
- if source in file_to_metric:
315
- file_to_metric[source].append(metric)
316
- else:
317
- file_to_metric[source] = [metric]
318
- return file_to_metric
317
+ file_to_metric.setdefault(source, []).append(metric)
318
+ return metric_primary_source, file_to_metric
319
319
 
320
320
 
321
321
  def get_files(chip, step, index):
@@ -1865,6 +1865,22 @@ def kill_process(chip, proc, tool, poll_interval, msg=""):
1865
1865
  utils.terminate_process(proc.pid)
1866
1866
 
1867
1867
 
1868
+ def get_check_node_keys(chip, step, index):
1869
+ tool, task = get_tool_task(chip, step, index)
1870
+
1871
+ # Collect keys to check for changes
1872
+ required = chip.get('tool', tool, 'task', task, 'require', step=step, index=index)
1873
+
1874
+ tool_task_key = ('tool', tool, 'task', task)
1875
+ for key in ('option', 'threads', 'prescript', 'postscript', 'refdir', 'script',):
1876
+ required.append(",".join([*tool_task_key, key]))
1877
+
1878
+ for env_key in chip.getkeys(*tool_task_key, 'env'):
1879
+ required.append(",".join([*tool_task_key, 'env', env_key]))
1880
+
1881
+ return set(sorted(required))
1882
+
1883
+
1868
1884
  def check_node_inputs(chip, step, index):
1869
1885
  from siliconcompiler import Chip # import here to avoid circular import
1870
1886
 
@@ -1918,15 +1934,8 @@ def check_node_inputs(chip, step, index):
1918
1934
  return False
1919
1935
 
1920
1936
  # Collect keys to check for changes
1921
- required = chip.get('tool', tool, 'task', task, 'require', step=step, index=index)
1922
- required.extend(input_chip.get('tool', tool, 'task', task, 'require', step=step, index=index))
1923
-
1924
- tool_task_key = ('tool', tool, 'task', task)
1925
- for key in ('option', 'threads', 'prescript', 'postscript', 'refdir', 'script',):
1926
- required.append(",".join([*tool_task_key, key]))
1927
- for check_chip in (chip, input_chip):
1928
- for env_key in check_chip.getkeys(*tool_task_key, 'env'):
1929
- required.append(",".join([*tool_task_key, 'env', env_key]))
1937
+ required = get_check_node_keys(chip, step, index)
1938
+ required.update(get_check_node_keys(input_chip, step, index))
1930
1939
 
1931
1940
  def print_warning(key, extra=None):
1932
1941
  if extra:
@@ -1937,7 +1946,7 @@ def check_node_inputs(chip, step, index):
1937
1946
  'from previous run')
1938
1947
 
1939
1948
  # Check if keys have been modified
1940
- for check_key in sorted(set(required)):
1949
+ for check_key in required:
1941
1950
  key = check_key.split(',')
1942
1951
 
1943
1952
  if not chip.valid(*key) or not input_chip.valid(*key):
@@ -1,7 +1,7 @@
1
1
  import docker
2
2
  import os
3
3
  from siliconcompiler.package import get_cache_path
4
- from siliconcompiler.package import _path as sc_path
4
+ from siliconcompiler.package import path as sc_path
5
5
  from siliconcompiler.utils import default_email_credentials_file
6
6
  from pathlib import Path
7
7
  import sys
@@ -47,7 +47,7 @@ def get_volumes_directories(chip, cache_dir, workdir, step, index):
47
47
 
48
48
  # Collect caches
49
49
  for package in chip.getkeys('package', 'source'):
50
- all_dirs.add(sc_path(chip, package, None))
50
+ all_dirs.add(sc_path(chip, package))
51
51
 
52
52
  all_dirs = [
53
53
  Path(cache_dir),
@@ -215,7 +215,7 @@ def run(chip, step, index, replay):
215
215
 
216
216
  cachemap = []
217
217
  for package in chip.getkeys('package', 'source'):
218
- cachemap.append(f'{package}:{sc_path(chip, package, None)}')
218
+ cachemap.append(f'{package}:{sc_path(chip, package)}')
219
219
 
220
220
  chip.logger.info(f'Running in docker container: {container.name} ({container.short_id})')
221
221
  args = [
@@ -5,7 +5,7 @@ import os
5
5
  import sys
6
6
  import tarfile
7
7
  from siliconcompiler import Chip, Schema
8
- from siliconcompiler.package import _path as sc_path
8
+ from siliconcompiler.package import path as sc_path
9
9
  from siliconcompiler.scheduler import _runtask, _executenode
10
10
  from siliconcompiler import __version__
11
11
 
@@ -45,6 +45,9 @@ def main():
45
45
  metavar='<package>:<directory>',
46
46
  nargs='+',
47
47
  help='Map of caches to prepopulate runner with')
48
+ parser.add_argument('-fetch_cache',
49
+ action='store_true',
50
+ help='Allow for cache downloads')
48
51
  parser.add_argument('-step',
49
52
  required=True,
50
53
  metavar='<step>',
@@ -103,9 +106,9 @@ def main():
103
106
  package, path = cachepair.split(':')
104
107
  chip._packages[package] = path
105
108
 
106
- # Populate cache without downloading
109
+ # Populate cache
107
110
  for package in chip.getkeys('package', 'source'):
108
- sc_path(chip, package, None)
111
+ sc_path(chip, package, fetch=args.fetch_cache)
109
112
 
110
113
  # Run the task.
111
114
  error = True
@@ -1092,6 +1092,10 @@ class Schema:
1092
1092
 
1093
1093
  tcl_set_cmds = []
1094
1094
  for key in self.allkeys():
1095
+ # print out all non default values
1096
+ if 'default' in key:
1097
+ continue
1098
+
1095
1099
  typestr = self.get(*key, field='type')
1096
1100
  pernode = self.get(*key, field='pernode')
1097
1101
 
@@ -1110,19 +1114,11 @@ class Schema:
1110
1114
 
1111
1115
  valstr = escape_val_tcl(value, typestr)
1112
1116
 
1113
- # Turning scalars into lists
1114
- if not (typestr.startswith('[') or typestr.startswith('(')):
1115
- valstr = f'[list {valstr}]'
1116
-
1117
- # TODO: Temp fix to get rid of empty args
1117
+ # Ensure empty values get something
1118
1118
  if valstr == '':
1119
- valstr = '[list ]'
1120
-
1121
- outstr = f"{prefix} {keystr} {valstr}"
1119
+ valstr = '{}'
1122
1120
 
1123
- # print out all non default values
1124
- if 'default' not in key:
1125
- tcl_set_cmds.append(outstr)
1121
+ tcl_set_cmds.append(f"{prefix} {keystr} {valstr}")
1126
1122
 
1127
1123
  if template:
1128
1124
  fout.write(template.render(manifest_dict='\n'.join(tcl_set_cmds),
@@ -34,7 +34,7 @@ proc sc_cfg_exists { args } {
34
34
 
35
35
  proc sc_top {} {
36
36
  set sc_entrypoint [sc_cfg_get option entrypoint]
37
- if {$sc_entrypoint == ""} {
37
+ if {$sc_entrypoint == {{ '{}' }}} {
38
38
  return [sc_cfg_get design]
39
39
  }
40
40
  return $sc_entrypoint
@@ -15,22 +15,20 @@ proc sc_collect_pin_constraints {
15
15
  set side [dict get $params side]
16
16
  set place [dict get $params placement]
17
17
 
18
- if { [llength $place] != 0 } {
18
+ if { $place != {} } {
19
19
  # Pin has placement information
20
- if { [llength $order] != 0 } {
20
+ if { $order != {} } {
21
21
  # Pin also has order information
22
22
  $print_func "Pin $name has placement specified in constraints, but also order."
23
23
  }
24
24
  lappend placement_pins $name
25
25
  } else {
26
26
  # Pin doesn't have placement
27
- if { [llength $side] == 0 || [llength $order] == 0 } {
27
+ if { $side == {} || $order == {} } {
28
28
  # Pin information is incomplete
29
29
  $print_func \
30
30
  "Warning: Pin $name doesn't have enough information to perform placement."
31
31
  } else {
32
- set side [lindex $side 0]
33
- set order [lindex $order 0]
34
32
  if { ![dict exists $pin_order $side $order] } {
35
33
  dict set pin_order $side $order []
36
34
  }
@@ -24,7 +24,7 @@ def make_docs(chip):
24
24
  def setup(chip):
25
25
  chip.set('tool', 'genfasm', 'exe', 'genfasm', clobber=False)
26
26
  chip.set('tool', 'genfasm', 'vswitch', '--version')
27
- chip.set('tool', 'genfasm', 'version', '>=8.1.0', clobber=False)
27
+ chip.set('tool', 'genfasm', 'version', '>=9.0.0', clobber=False)
28
28
 
29
29
  add_tool_requirements(chip)
30
30
 
@@ -84,12 +84,16 @@ def extract_metrics(chip):
84
84
  metric_reports = {
85
85
  "setuptns": [
86
86
  "timing/total_negative_slack.rpt",
87
- "timing/setup.rpt"
87
+ "timing/setup.rpt",
88
+ "timing/setup.histogram.rpt",
89
+ "images/timing/setup.histogram.png"
88
90
  ],
89
91
  "setupslack": [
90
92
  "timing/worst_slack.setup.rpt",
91
93
  "timing/setup.rpt",
92
- "timing/setup.topN.rpt"
94
+ "timing/setup.topN.rpt",
95
+ "timing/setup.histogram.rpt",
96
+ "images/timing/setup.histogram.png"
93
97
  ],
94
98
  "setupskew": [
95
99
  "timing/skew.setup.rpt",
@@ -99,12 +103,16 @@ def extract_metrics(chip):
99
103
  ],
100
104
  "setuppaths": [
101
105
  "timing/setup.rpt",
102
- "timing/setup.topN.rpt"
106
+ "timing/setup.topN.rpt",
107
+ "timing/setup.histogram.rpt",
108
+ "images/timing/setup.histogram.png"
103
109
  ],
104
110
  "holdslack": [
105
111
  "timing/worst_slack.hold.rpt",
106
112
  "timing/hold.rpt",
107
- "timing/hold.topN.rpt"
113
+ "timing/hold.topN.rpt",
114
+ "timing/hold.histogram.rpt",
115
+ "images/timing/hold.histogram.png"
108
116
  ],
109
117
  "holdskew": [
110
118
  "timing/skew.hold.rpt",
@@ -114,7 +122,9 @@ def extract_metrics(chip):
114
122
  ],
115
123
  "holdpaths": [
116
124
  "timing/hold.rpt",
117
- "timing/hold.topN.rpt"
125
+ "timing/hold.topN.rpt",
126
+ "timing/hold.histogram.rpt",
127
+ "images/timing/hold.histogram.png"
118
128
  ],
119
129
  "unconstrained": [
120
130
  "timing/unconstrained.rpt",
@@ -75,6 +75,10 @@ def setup(chip):
75
75
  'if enabled by the PDK, to the design',
76
76
  skip='lib')
77
77
 
78
+ chip.set('tool', tool, 'task', task, 'var', 'debug_level',
79
+ 'list of "tool key level" to enable debugging of OpenROAD',
80
+ field='help')
81
+
78
82
  if f'{design}.v' in input_provides(chip, step, index):
79
83
  chip.add('tool', tool, 'task', task, 'input', design + '.v', step=step, index=index)
80
84
  elif f'{design}.vg' in input_provides(chip, step, index):
@@ -121,11 +121,11 @@ if { [sc_cfg_exists constraint pin] } {
121
121
  global sc_vpinmetal
122
122
 
123
123
  set layer [sc_cfg_get constraint pin $pin layer]
124
- if { [llength $layer] != 0 } {
125
- return [sc_get_layer_name [lindex $layer 0]]
124
+ if { $layer != {} } {
125
+ return [sc_get_layer_name $layer]
126
126
  }
127
127
  set side [sc_cfg_get constraint pin $pin side]
128
- if { [llength $side] != 0 } {
128
+ if { $side != {} } {
129
129
  switch -regexp $side {
130
130
  "1|3" {
131
131
  return [lindex $sc_hpinmetal 0]
@@ -27,6 +27,11 @@ if { [sc_cfg_tool_task_check_in_list setup var reports] } {
27
27
  tee -file reports/timing/total_negative_slack.rpt \
28
28
  "report_tns"
29
29
  report_tns_metric -setup
30
+
31
+ if { [sc_check_version 19519] } {
32
+ tee -quiet -file reports/timing/setup.histogram.rpt \
33
+ "report_timing_histogram -num_bins 20 -setup"
34
+ }
30
35
  }
31
36
 
32
37
  if { [sc_cfg_tool_task_check_in_list hold var reports] } {
@@ -42,6 +47,11 @@ if { [sc_cfg_tool_task_check_in_list hold var reports] } {
42
47
  report_worst_slack_metric -hold
43
48
 
44
49
  report_tns_metric -hold
50
+
51
+ if { [sc_check_version 19519] } {
52
+ tee -quiet -file reports/timing/hold.histogram.rpt \
53
+ "report_timing_histogram -num_bins 20 -hold"
54
+ }
45
55
  }
46
56
 
47
57
  if { [sc_cfg_tool_task_check_in_list unconstrained var reports] } {
@@ -304,6 +304,30 @@ proc sc_image_clocktree { } {
304
304
  gui::hide_widget "Clock Tree Viewer"
305
305
  }
306
306
 
307
+ proc sc_image_timing_histograms { } {
308
+ if { ![sc_check_version 19526] } {
309
+ return
310
+ }
311
+ file mkdir reports/images/timing
312
+
313
+ if { [sc_cfg_tool_task_check_in_list setup var reports] } {
314
+ set path reports/images/timing/setup.histogram.png
315
+ utl::info FLW 1 "Saving setup timing histogram to $path"
316
+ save_histogram_image $path \
317
+ -mode setup \
318
+ -width 500 \
319
+ -height 500
320
+ }
321
+ if { [sc_cfg_tool_task_check_in_list hold var reports] } {
322
+ set path reports/images/timing/hold.histogram.png
323
+ utl::info FLW 1 "Saving hold timing histogram to $path"
324
+ save_histogram_image $path \
325
+ -mode hold \
326
+ -width 500 \
327
+ -height 500
328
+ }
329
+ }
330
+
307
331
  proc sc_image_optimizer { } {
308
332
  global sc_design
309
333
  sc_image_setup_default
@@ -390,6 +414,9 @@ if { [sc_cfg_tool_task_check_in_list module_view var reports] } {
390
414
  # Markers
391
415
  sc_image_markers
392
416
 
417
+ # Histograms
418
+ sc_image_timing_histograms
419
+
393
420
  # Heatmaps
394
421
  if { [sc_cfg_tool_task_check_in_list placement_density var reports] } {
395
422
  sc_image_placement_density
@@ -35,21 +35,11 @@ set sc_threads [sc_cfg_tool_task_get threads]
35
35
  # MACROS
36
36
  set sc_macrolibs [sc_get_asic_libraries macro]
37
37
 
38
- ###############################
39
- # Suppress messages if requested
38
+ ##############################
39
+ # Setup debugging
40
40
  ###############################
41
41
 
42
- foreach msg [sc_cfg_tool_task_get warningoff] {
43
- set or_msg [split $msg "-"]
44
- if { [llength $or_msg] != 2 } {
45
- utl::warn FLW 1 "$msg is not a valid message id"
46
- } else {
47
- set or_tool [lindex $or_msg 0]
48
- set or_msg_id [expr { int([lindex $or_msg 1]) }]
49
- utl::info FLW 1 "Suppressing $msg messages"
50
- suppress_message $or_tool $or_msg_id
51
- }
52
- }
42
+ source -echo "$sc_refdir/common/debugging.tcl"
53
43
 
54
44
  ###############################
55
45
  # Source helper functions