librelane 2.4.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.

Potentially problematic release.


This version of librelane might be problematic. Click here for more details.

Files changed (170) hide show
  1. librelane/__init__.py +38 -0
  2. librelane/__main__.py +479 -0
  3. librelane/__version__.py +43 -0
  4. librelane/common/__init__.py +63 -0
  5. librelane/common/cli.py +75 -0
  6. librelane/common/drc.py +246 -0
  7. librelane/common/generic_dict.py +319 -0
  8. librelane/common/metrics/__init__.py +35 -0
  9. librelane/common/metrics/__main__.py +413 -0
  10. librelane/common/metrics/library.py +354 -0
  11. librelane/common/metrics/metric.py +186 -0
  12. librelane/common/metrics/util.py +279 -0
  13. librelane/common/misc.py +456 -0
  14. librelane/common/ring_buffer.py +63 -0
  15. librelane/common/tcl.py +80 -0
  16. librelane/common/toolbox.py +549 -0
  17. librelane/common/tpe.py +41 -0
  18. librelane/common/types.py +116 -0
  19. librelane/config/__init__.py +32 -0
  20. librelane/config/__main__.py +155 -0
  21. librelane/config/config.py +1025 -0
  22. librelane/config/flow.py +490 -0
  23. librelane/config/pdk_compat.py +255 -0
  24. librelane/config/preprocessor.py +464 -0
  25. librelane/config/removals.py +45 -0
  26. librelane/config/variable.py +743 -0
  27. librelane/container.py +285 -0
  28. librelane/env_info.py +320 -0
  29. librelane/examples/spm/config.yaml +33 -0
  30. librelane/examples/spm/pin_order.cfg +14 -0
  31. librelane/examples/spm/src/impl.sdc +73 -0
  32. librelane/examples/spm/src/signoff.sdc +68 -0
  33. librelane/examples/spm/src/spm.v +73 -0
  34. librelane/examples/spm/verify/spm_tb.v +106 -0
  35. librelane/examples/spm-user_project_wrapper/SPM_example.v +286 -0
  36. librelane/examples/spm-user_project_wrapper/base_sdc_file.sdc +145 -0
  37. librelane/examples/spm-user_project_wrapper/config-tut.json +12 -0
  38. librelane/examples/spm-user_project_wrapper/config.json +13 -0
  39. librelane/examples/spm-user_project_wrapper/defines.v +66 -0
  40. librelane/examples/spm-user_project_wrapper/template.def +7656 -0
  41. librelane/examples/spm-user_project_wrapper/user_project_wrapper.v +123 -0
  42. librelane/flows/__init__.py +24 -0
  43. librelane/flows/builtins.py +18 -0
  44. librelane/flows/classic.py +327 -0
  45. librelane/flows/cli.py +463 -0
  46. librelane/flows/flow.py +1049 -0
  47. librelane/flows/misc.py +71 -0
  48. librelane/flows/optimizing.py +179 -0
  49. librelane/flows/sequential.py +367 -0
  50. librelane/flows/synth_explore.py +173 -0
  51. librelane/help/__main__.py +39 -0
  52. librelane/logging/__init__.py +40 -0
  53. librelane/logging/logger.py +323 -0
  54. librelane/open_pdks_rev +1 -0
  55. librelane/plugins.py +21 -0
  56. librelane/py.typed +0 -0
  57. librelane/scripts/base.sdc +80 -0
  58. librelane/scripts/klayout/Readme.md +2 -0
  59. librelane/scripts/klayout/open_design.py +63 -0
  60. librelane/scripts/klayout/render.py +121 -0
  61. librelane/scripts/klayout/stream_out.py +176 -0
  62. librelane/scripts/klayout/xml_drc_report_to_json.py +45 -0
  63. librelane/scripts/klayout/xor.drc +120 -0
  64. librelane/scripts/magic/Readme.md +1 -0
  65. librelane/scripts/magic/common/read.tcl +114 -0
  66. librelane/scripts/magic/def/antenna_check.tcl +35 -0
  67. librelane/scripts/magic/def/mag.tcl +19 -0
  68. librelane/scripts/magic/def/mag_gds.tcl +79 -0
  69. librelane/scripts/magic/drc.tcl +78 -0
  70. librelane/scripts/magic/extract_spice.tcl +98 -0
  71. librelane/scripts/magic/gds/drc_batch.tcl +74 -0
  72. librelane/scripts/magic/gds/erase_box.tcl +32 -0
  73. librelane/scripts/magic/gds/extras_mag.tcl +45 -0
  74. librelane/scripts/magic/gds/mag_with_pointers.tcl +31 -0
  75. librelane/scripts/magic/get_bbox.tcl +11 -0
  76. librelane/scripts/magic/lef/extras_maglef.tcl +61 -0
  77. librelane/scripts/magic/lef/maglef.tcl +26 -0
  78. librelane/scripts/magic/lef.tcl +57 -0
  79. librelane/scripts/magic/open.tcl +28 -0
  80. librelane/scripts/magic/wrapper.tcl +21 -0
  81. librelane/scripts/netgen/setup.tcl +28 -0
  82. librelane/scripts/odbpy/apply_def_template.py +49 -0
  83. librelane/scripts/odbpy/cell_frequency.py +107 -0
  84. librelane/scripts/odbpy/check_antenna_properties.py +116 -0
  85. librelane/scripts/odbpy/contextualize.py +109 -0
  86. librelane/scripts/odbpy/defutil.py +573 -0
  87. librelane/scripts/odbpy/diodes.py +373 -0
  88. librelane/scripts/odbpy/disconnected_pins.py +305 -0
  89. librelane/scripts/odbpy/eco_buffer.py +181 -0
  90. librelane/scripts/odbpy/eco_diode.py +139 -0
  91. librelane/scripts/odbpy/filter_unannotated.py +100 -0
  92. librelane/scripts/odbpy/io_place.py +482 -0
  93. librelane/scripts/odbpy/ioplace_parser/__init__.py +23 -0
  94. librelane/scripts/odbpy/ioplace_parser/parse.py +147 -0
  95. librelane/scripts/odbpy/label_macro_pins.py +277 -0
  96. librelane/scripts/odbpy/lefutil.py +97 -0
  97. librelane/scripts/odbpy/placers.py +162 -0
  98. librelane/scripts/odbpy/power_utils.py +397 -0
  99. librelane/scripts/odbpy/random_place.py +57 -0
  100. librelane/scripts/odbpy/reader.py +250 -0
  101. librelane/scripts/odbpy/remove_buffers.py +173 -0
  102. librelane/scripts/odbpy/snap_to_grid.py +57 -0
  103. librelane/scripts/odbpy/wire_lengths.py +93 -0
  104. librelane/scripts/openroad/antenna_check.tcl +20 -0
  105. librelane/scripts/openroad/antenna_repair.tcl +31 -0
  106. librelane/scripts/openroad/basic_mp.tcl +24 -0
  107. librelane/scripts/openroad/buffer_list.tcl +10 -0
  108. librelane/scripts/openroad/common/dpl.tcl +24 -0
  109. librelane/scripts/openroad/common/dpl_cell_pad.tcl +26 -0
  110. librelane/scripts/openroad/common/grt.tcl +32 -0
  111. librelane/scripts/openroad/common/io.tcl +540 -0
  112. librelane/scripts/openroad/common/pdn_cfg.tcl +135 -0
  113. librelane/scripts/openroad/common/resizer.tcl +103 -0
  114. librelane/scripts/openroad/common/set_global_connections.tcl +78 -0
  115. librelane/scripts/openroad/common/set_layer_adjustments.tcl +31 -0
  116. librelane/scripts/openroad/common/set_power_nets.tcl +30 -0
  117. librelane/scripts/openroad/common/set_rc.tcl +75 -0
  118. librelane/scripts/openroad/common/set_routing_layers.tcl +30 -0
  119. librelane/scripts/openroad/cts.tcl +80 -0
  120. librelane/scripts/openroad/cut_rows.tcl +24 -0
  121. librelane/scripts/openroad/dpl.tcl +24 -0
  122. librelane/scripts/openroad/drt.tcl +37 -0
  123. librelane/scripts/openroad/fill.tcl +30 -0
  124. librelane/scripts/openroad/floorplan.tcl +145 -0
  125. librelane/scripts/openroad/gpl.tcl +88 -0
  126. librelane/scripts/openroad/grt.tcl +30 -0
  127. librelane/scripts/openroad/gui.tcl +37 -0
  128. librelane/scripts/openroad/insert_buffer.tcl +127 -0
  129. librelane/scripts/openroad/ioplacer.tcl +67 -0
  130. librelane/scripts/openroad/irdrop.tcl +51 -0
  131. librelane/scripts/openroad/pdn.tcl +52 -0
  132. librelane/scripts/openroad/rcx.tcl +32 -0
  133. librelane/scripts/openroad/repair_design.tcl +70 -0
  134. librelane/scripts/openroad/repair_design_postgrt.tcl +48 -0
  135. librelane/scripts/openroad/rsz_timing_postcts.tcl +68 -0
  136. librelane/scripts/openroad/rsz_timing_postgrt.tcl +70 -0
  137. librelane/scripts/openroad/sta/check_macro_instances.tcl +53 -0
  138. librelane/scripts/openroad/sta/corner.tcl +393 -0
  139. librelane/scripts/openroad/tapcell.tcl +25 -0
  140. librelane/scripts/openroad/write_views.tcl +27 -0
  141. librelane/scripts/pyosys/construct_abc_script.py +177 -0
  142. librelane/scripts/pyosys/json_header.py +84 -0
  143. librelane/scripts/pyosys/synthesize.py +493 -0
  144. librelane/scripts/pyosys/ys_common.py +153 -0
  145. librelane/scripts/tclsh/hello.tcl +1 -0
  146. librelane/state/__init__.py +24 -0
  147. librelane/state/__main__.py +61 -0
  148. librelane/state/design_format.py +195 -0
  149. librelane/state/state.py +359 -0
  150. librelane/steps/__init__.py +61 -0
  151. librelane/steps/__main__.py +510 -0
  152. librelane/steps/checker.py +637 -0
  153. librelane/steps/common_variables.py +340 -0
  154. librelane/steps/cvc_rv.py +169 -0
  155. librelane/steps/klayout.py +509 -0
  156. librelane/steps/magic.py +576 -0
  157. librelane/steps/misc.py +160 -0
  158. librelane/steps/netgen.py +253 -0
  159. librelane/steps/odb.py +1088 -0
  160. librelane/steps/openroad.py +2460 -0
  161. librelane/steps/openroad_alerts.py +102 -0
  162. librelane/steps/pyosys.py +640 -0
  163. librelane/steps/step.py +1571 -0
  164. librelane/steps/tclstep.py +288 -0
  165. librelane/steps/verilator.py +222 -0
  166. librelane/steps/yosys.py +371 -0
  167. librelane-2.4.0.dist-info/METADATA +169 -0
  168. librelane-2.4.0.dist-info/RECORD +170 -0
  169. librelane-2.4.0.dist-info/WHEEL +4 -0
  170. librelane-2.4.0.dist-info/entry_points.txt +9 -0
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2025 Efabless Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import sys
16
+ from reader import click_odb, click, odb
17
+ import grt as GRT
18
+
19
+
20
+ def average_location(instances):
21
+ locations = [instance.getLocation() for instance in instances]
22
+ x_sum = sum(loc[0] for loc in locations)
23
+ y_sum = sum(loc[1] for loc in locations)
24
+ return (x_sum // len(locations), y_sum // len(locations))
25
+
26
+
27
+ @click.command()
28
+ @click_odb
29
+ def cli(reader):
30
+ grt = reader.design.getGlobalRouter()
31
+ dpl = reader.design.getOpendp()
32
+
33
+ insts_to_temporarily_lock_then_unlock_later = []
34
+ for inst in reader.block.getInsts():
35
+ if inst.getPlacementStatus() != "LOCKED":
36
+ insts_to_temporarily_lock_then_unlock_later.append(
37
+ (inst, inst.getPlacementStatus())
38
+ )
39
+ inst.setPlacementStatus("LOCKED")
40
+
41
+ reader._grt_setup(grt)
42
+
43
+ grt_inc = GRT.IncrementalGRoute(grt, reader.block)
44
+ i = 0
45
+
46
+ for target_info in reader.config["INSERT_ECO_BUFFERS"]:
47
+ target_name, target_pin = target_info["target"].split("/")
48
+ name_escaped = reader.escape_verilog_name(target_name)
49
+ buffer_master = target_info["buffer"]
50
+
51
+ master = reader.db.findMaster(buffer_master)
52
+ if master is None:
53
+ print(
54
+ f"[ERROR] Buffer type '{buffer_master}' not found.",
55
+ file=sys.stderr,
56
+ )
57
+ exit(-1)
58
+
59
+ target = reader.block.findInst(name_escaped)
60
+ if target is None:
61
+ print(f"[ERROR] Instance '{target_name}' not found.", file=sys.stderr)
62
+ exit(-1)
63
+
64
+ target_iterm = target.findITerm(target_pin)
65
+ if target_iterm is None:
66
+ print(
67
+ f"[ERROR] Pin '{target_pin}' not found for instance '{target_name}'.",
68
+ file=sys.stderr,
69
+ )
70
+ exit(-1)
71
+
72
+ net = target_iterm.getNet()
73
+ if net is None:
74
+ print(
75
+ f"[ERROR] Net not found on pin '{target_pin}' of instance '{target_name}'.",
76
+ file=sys.stderr,
77
+ )
78
+ exit(-1)
79
+
80
+ new_buf_name = f"eco_buffer_{i}"
81
+ new_net_name = f"eco_buffer_{i}_net"
82
+ while (
83
+ reader.block.findInst(new_buf_name) is not None
84
+ or reader.block.findNet(new_net_name) is not None
85
+ ):
86
+ i += 1
87
+ new_buf_name = f"eco_buffer_{i}"
88
+ new_net_name = f"eco_buffer_{i}_net"
89
+
90
+ # Prepare buffer cell, net
91
+ eco_buffer = odb.dbInst.create(reader.block, master, new_buf_name)
92
+ eco_net = odb.dbNet.create(reader.block, new_net_name)
93
+ buffer_iterms = eco_buffer.getITerms()
94
+ buffer_a = None
95
+ for iterm in buffer_iterms:
96
+ if iterm.isInputSignal():
97
+ buffer_a = iterm
98
+ break # Exit loop once input is found
99
+ if buffer_a is None:
100
+ print(
101
+ f"[ERROR] Buffer {buffer_master} has no input signals.",
102
+ file=sys.stderr,
103
+ )
104
+ exit(-1)
105
+
106
+ buffer_x = None
107
+ for iterm in buffer_iterms:
108
+ if iterm.isOutputSignal():
109
+ buffer_x = iterm
110
+ break # Exit loop once output is found
111
+ if buffer_x is None:
112
+ print(
113
+ f"[ERROR] Buffer {buffer_master} has no output signals.",
114
+ file=sys.stderr,
115
+ )
116
+ exit(-1)
117
+
118
+ location_instances = [target]
119
+ net_iterms = net.getITerms()
120
+ if target_iterm.getIoType() == "INPUT":
121
+ driver_iterms = [
122
+ iterm for iterm in net_iterms if iterm.getIoType() in ["OUTPUT"]
123
+ ]
124
+ drivers = [iterm.getInst() for iterm in driver_iterms]
125
+ location_instances.extend(drivers)
126
+
127
+ target_iterm.disconnect()
128
+ buffer_a.connect(net)
129
+ buffer_x.connect(eco_net)
130
+ target_iterm.connect(eco_net)
131
+ elif target_iterm.getIoType() == "OUTPUT":
132
+ sink_iterms = [
133
+ iterm for iterm in net_iterms if iterm.getIoType() in ["INPUT", "INOUT"]
134
+ ]
135
+ sinks = [iterm.getInst() for iterm in sink_iterms]
136
+ location_instances.extend(sinks)
137
+
138
+ target_iterm.disconnect()
139
+ target_iterm.connect(eco_net)
140
+ buffer_a.connect(eco_net)
141
+ buffer_x.connect(net)
142
+ else:
143
+ print(
144
+ f"[ERROR] {target_name}/{target_pin} is neither an INPUT or an OUTPUT and is unsupported by this script. To buffer an INOUT port, buffer its drivers instead.",
145
+ file=sys.stderr,
146
+ )
147
+ exit(-1)
148
+
149
+ if target_info.get("placement") is not None:
150
+ eco_x, eco_y = target_info["placement"]
151
+ eco_x = reader.block.micronsToDbu(float(eco_x))
152
+ eco_y = reader.block.micronsToDbu(float(eco_y))
153
+ eco_loc = (eco_x, eco_y)
154
+ else:
155
+ eco_loc = average_location(location_instances)
156
+
157
+ eco_buffer.setOrient("R0")
158
+ eco_buffer.setLocation(*eco_loc)
159
+ eco_buffer.setPlacementStatus("PLACED")
160
+ grt.addDirtyNet(net)
161
+ grt.addDirtyNet(eco_net)
162
+
163
+ site = reader.rows[0].getSite()
164
+ max_disp_x = int(
165
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_X"])
166
+ / site.getWidth()
167
+ )
168
+ max_disp_y = int(
169
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_Y"])
170
+ / site.getHeight()
171
+ )
172
+ dpl.detailedPlacement(max_disp_x, max_disp_y)
173
+
174
+ grt_inc.updateRoutes(True)
175
+
176
+ for inst, previous_status in insts_to_temporarily_lock_then_unlock_later:
177
+ inst.setPlacementStatus(previous_status)
178
+
179
+
180
+ if __name__ == "__main__":
181
+ cli()
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2025 Efabless Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import sys
16
+ from reader import click_odb, click, odb
17
+ import grt as GRT
18
+
19
+
20
+ @click.command()
21
+ @click_odb
22
+ def cli(reader):
23
+ grt = reader.design.getGlobalRouter()
24
+ dpl = reader.design.getOpendp()
25
+
26
+ insts_to_temporarily_lock_then_unlock_later = []
27
+ for inst in reader.block.getInsts():
28
+ if inst.getPlacementStatus() != "LOCKED":
29
+ insts_to_temporarily_lock_then_unlock_later.append(
30
+ (inst, inst.getPlacementStatus())
31
+ )
32
+ inst.setPlacementStatus("LOCKED")
33
+
34
+ reader._grt_setup(grt)
35
+
36
+ diode_master, diode_pin = reader.config["DIODE_CELL"].split("/")
37
+
38
+ # print(grt)
39
+ grt_inc = GRT.IncrementalGRoute(grt, reader.block)
40
+ i = 0
41
+ for target_info in reader.config["INSERT_ECO_DIODES"]:
42
+ target_name, target_pin = target_info["target"].split("/")
43
+ name_escaped = reader.escape_verilog_name(target_name)
44
+
45
+ target = reader.block.findInst(name_escaped)
46
+ if target is None:
47
+ print(
48
+ f"[ERROR] Instance '{target_name}' not found.",
49
+ file=sys.stderr,
50
+ )
51
+ exit(-1)
52
+
53
+ master = reader.db.findMaster(diode_master)
54
+ if master is None:
55
+ print(
56
+ f"[ERROR] Cell kind '{diode_master}' not found.",
57
+ file=sys.stderr,
58
+ )
59
+ exit(-1)
60
+
61
+ target_iterm = target.findITerm(target_pin)
62
+ if target_iterm is None:
63
+ print(
64
+ f"[ERROR] Pin '{target_pin}' not found for instance {target_name}.",
65
+ file=sys.stderr,
66
+ )
67
+ exit(-1)
68
+
69
+ if target_iterm.getIoType() not in ["INPUT", "INOUT"]:
70
+ print(
71
+ f"[ERROR] Pin {target_info['target']} is an OUTPUT pin.",
72
+ file=sys.stderr,
73
+ )
74
+ exit(-1)
75
+
76
+ net = target_iterm.getNet()
77
+ if net is None:
78
+ print(
79
+ f"[ERROR] Pin {target_info['target']} has no nets connected.",
80
+ file=sys.stderr,
81
+ )
82
+ exit(-1)
83
+
84
+ eco_diode_name = f"eco_diode_{i}"
85
+ while reader.block.findInst(eco_diode_name) is not None:
86
+ i += 1
87
+ eco_diode_name = f"eco_diode_{i}"
88
+
89
+ eco_diode = odb.dbInst.create(
90
+ reader.block,
91
+ master,
92
+ eco_diode_name,
93
+ )
94
+
95
+ diode_iterm = eco_diode.findITerm(diode_pin)
96
+ if diode_iterm is None:
97
+ print(
98
+ f"[ERROR] Pin '{diode_pin}' on ECO diode not found- invalid DIODE_CELL definition.",
99
+ file=sys.stderr,
100
+ )
101
+ exit(-1)
102
+
103
+ sys.stdout.flush()
104
+
105
+ if target_info["placement"] is not None:
106
+ x, y = target_info["placement"]
107
+ x = reader.block.micronsToDbu(float(x))
108
+ y = reader.block.micronsToDbu(float(y))
109
+ else:
110
+ x, y = target.getLocation()
111
+
112
+ eco_diode.setOrient("R0")
113
+ eco_diode.setLocation(x, y)
114
+ eco_diode.setPlacementStatus("PLACED")
115
+
116
+ diode_iterm.connect(net)
117
+ grt.addDirtyNet(net)
118
+
119
+ site = reader.rows[0].getSite()
120
+ max_disp_x = int(
121
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_X"])
122
+ / site.getWidth()
123
+ )
124
+ max_disp_y = int(
125
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_Y"])
126
+ / site.getHeight()
127
+ )
128
+ dpl.detailedPlacement(max_disp_x, max_disp_y)
129
+
130
+ grt_inc.updateRoutes(True)
131
+
132
+ for inst, previous_status in insts_to_temporarily_lock_then_unlock_later:
133
+ inst.setPlacementStatus(previous_status)
134
+
135
+ reader.design.writeDef("out.def")
136
+
137
+
138
+ if __name__ == "__main__":
139
+ cli()
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2023 Efabless Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this report except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import re
16
+ import pprint
17
+ from collections import namedtuple
18
+
19
+ from reader import click_odb, click
20
+
21
+ import odb
22
+ import utl
23
+
24
+
25
+ def filter_net(net: odb.dbNet) -> bool:
26
+ # wire is the physical implementation of a net.
27
+ # if a net has no wire. there is no problem for it being unannotated
28
+ return net.getWire() is not None
29
+
30
+
31
+ @click.option("--corner")
32
+ @click.option("--checks-report", "checks_report")
33
+ @click.command()
34
+ @click_odb
35
+ def main(reader, corner, checks_report):
36
+ Net = namedtuple("Net", "name bterms")
37
+ BTerm = namedtuple("BTerm", "name type")
38
+
39
+ db = reader.db
40
+ block = db.getChip().getBlock()
41
+ nets = block.getNets()
42
+
43
+ report_content = []
44
+ with open(checks_report, "r") as f:
45
+ report_content = f.readlines()
46
+
47
+ annotation_report_start = "report_parasitic_annotation -report_unannotated\n"
48
+ annotation_report_end = (
49
+ "===========================================================================\n"
50
+ )
51
+ start_index = report_content.index(annotation_report_start)
52
+ end_index = report_content.index(annotation_report_end, start_index)
53
+
54
+ print("Unannotated report:")
55
+ pprint.pprint(report_content[start_index:end_index])
56
+
57
+ # Sample report:
58
+ # Found 324 unannotated drivers.
59
+ # analog_io[0]
60
+ # analog_io[10]
61
+ # analog_io[11]
62
+ # Found 68 partially unannotated drivers.
63
+ # wbs_adr_i[0]
64
+ # mprj/wbs_adr_i[31]
65
+ # wbs_adr_i[10]
66
+ # mprj/wbs_adr_i[21]
67
+ # wbs_adr_i[11]
68
+ # ....
69
+
70
+ reported_nets = [
71
+ line.rstrip().lstrip()
72
+ for line in report_content[start_index:end_index]
73
+ if re.match(r" \S+", line)
74
+ ]
75
+ print("Reported nets:")
76
+ pprint.pprint(reported_nets)
77
+ connected_nets = [
78
+ Net(
79
+ name=net.getName(),
80
+ bterms=[
81
+ BTerm(bterm.getName(), bterm.getIoType()) for bterm in net.getBTerms()
82
+ ],
83
+ )
84
+ for net in nets
85
+ if (net.getName() in reported_nets) and filter_net(net)
86
+ ]
87
+ print("Filtered nets:")
88
+ pprint.pprint(connected_nets)
89
+ utl.metric_integer(
90
+ f"timing__unannotated_net__count__corner:{corner}", len(reported_nets)
91
+ )
92
+ utl.metric_integer(
93
+ f"timing__unannotated_net_filtered__count__corner:{corner}",
94
+ len(connected_nets),
95
+ )
96
+ print("done")
97
+
98
+
99
+ if __name__ == "__main__":
100
+ main()