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.
- librelane/__init__.py +38 -0
- librelane/__main__.py +479 -0
- librelane/__version__.py +43 -0
- librelane/common/__init__.py +63 -0
- librelane/common/cli.py +75 -0
- librelane/common/drc.py +246 -0
- librelane/common/generic_dict.py +319 -0
- librelane/common/metrics/__init__.py +35 -0
- librelane/common/metrics/__main__.py +413 -0
- librelane/common/metrics/library.py +354 -0
- librelane/common/metrics/metric.py +186 -0
- librelane/common/metrics/util.py +279 -0
- librelane/common/misc.py +456 -0
- librelane/common/ring_buffer.py +63 -0
- librelane/common/tcl.py +80 -0
- librelane/common/toolbox.py +549 -0
- librelane/common/tpe.py +41 -0
- librelane/common/types.py +116 -0
- librelane/config/__init__.py +32 -0
- librelane/config/__main__.py +155 -0
- librelane/config/config.py +1025 -0
- librelane/config/flow.py +490 -0
- librelane/config/pdk_compat.py +255 -0
- librelane/config/preprocessor.py +464 -0
- librelane/config/removals.py +45 -0
- librelane/config/variable.py +743 -0
- librelane/container.py +285 -0
- librelane/env_info.py +320 -0
- librelane/examples/spm/config.yaml +33 -0
- librelane/examples/spm/pin_order.cfg +14 -0
- librelane/examples/spm/src/impl.sdc +73 -0
- librelane/examples/spm/src/signoff.sdc +68 -0
- librelane/examples/spm/src/spm.v +73 -0
- librelane/examples/spm/verify/spm_tb.v +106 -0
- librelane/examples/spm-user_project_wrapper/SPM_example.v +286 -0
- librelane/examples/spm-user_project_wrapper/base_sdc_file.sdc +145 -0
- librelane/examples/spm-user_project_wrapper/config-tut.json +12 -0
- librelane/examples/spm-user_project_wrapper/config.json +13 -0
- librelane/examples/spm-user_project_wrapper/defines.v +66 -0
- librelane/examples/spm-user_project_wrapper/template.def +7656 -0
- librelane/examples/spm-user_project_wrapper/user_project_wrapper.v +123 -0
- librelane/flows/__init__.py +24 -0
- librelane/flows/builtins.py +18 -0
- librelane/flows/classic.py +327 -0
- librelane/flows/cli.py +463 -0
- librelane/flows/flow.py +1049 -0
- librelane/flows/misc.py +71 -0
- librelane/flows/optimizing.py +179 -0
- librelane/flows/sequential.py +367 -0
- librelane/flows/synth_explore.py +173 -0
- librelane/help/__main__.py +39 -0
- librelane/logging/__init__.py +40 -0
- librelane/logging/logger.py +323 -0
- librelane/open_pdks_rev +1 -0
- librelane/plugins.py +21 -0
- librelane/py.typed +0 -0
- librelane/scripts/base.sdc +80 -0
- librelane/scripts/klayout/Readme.md +2 -0
- librelane/scripts/klayout/open_design.py +63 -0
- librelane/scripts/klayout/render.py +121 -0
- librelane/scripts/klayout/stream_out.py +176 -0
- librelane/scripts/klayout/xml_drc_report_to_json.py +45 -0
- librelane/scripts/klayout/xor.drc +120 -0
- librelane/scripts/magic/Readme.md +1 -0
- librelane/scripts/magic/common/read.tcl +114 -0
- librelane/scripts/magic/def/antenna_check.tcl +35 -0
- librelane/scripts/magic/def/mag.tcl +19 -0
- librelane/scripts/magic/def/mag_gds.tcl +79 -0
- librelane/scripts/magic/drc.tcl +78 -0
- librelane/scripts/magic/extract_spice.tcl +98 -0
- librelane/scripts/magic/gds/drc_batch.tcl +74 -0
- librelane/scripts/magic/gds/erase_box.tcl +32 -0
- librelane/scripts/magic/gds/extras_mag.tcl +45 -0
- librelane/scripts/magic/gds/mag_with_pointers.tcl +31 -0
- librelane/scripts/magic/get_bbox.tcl +11 -0
- librelane/scripts/magic/lef/extras_maglef.tcl +61 -0
- librelane/scripts/magic/lef/maglef.tcl +26 -0
- librelane/scripts/magic/lef.tcl +57 -0
- librelane/scripts/magic/open.tcl +28 -0
- librelane/scripts/magic/wrapper.tcl +21 -0
- librelane/scripts/netgen/setup.tcl +28 -0
- librelane/scripts/odbpy/apply_def_template.py +49 -0
- librelane/scripts/odbpy/cell_frequency.py +107 -0
- librelane/scripts/odbpy/check_antenna_properties.py +116 -0
- librelane/scripts/odbpy/contextualize.py +109 -0
- librelane/scripts/odbpy/defutil.py +573 -0
- librelane/scripts/odbpy/diodes.py +373 -0
- librelane/scripts/odbpy/disconnected_pins.py +305 -0
- librelane/scripts/odbpy/eco_buffer.py +181 -0
- librelane/scripts/odbpy/eco_diode.py +139 -0
- librelane/scripts/odbpy/filter_unannotated.py +100 -0
- librelane/scripts/odbpy/io_place.py +482 -0
- librelane/scripts/odbpy/ioplace_parser/__init__.py +23 -0
- librelane/scripts/odbpy/ioplace_parser/parse.py +147 -0
- librelane/scripts/odbpy/label_macro_pins.py +277 -0
- librelane/scripts/odbpy/lefutil.py +97 -0
- librelane/scripts/odbpy/placers.py +162 -0
- librelane/scripts/odbpy/power_utils.py +397 -0
- librelane/scripts/odbpy/random_place.py +57 -0
- librelane/scripts/odbpy/reader.py +250 -0
- librelane/scripts/odbpy/remove_buffers.py +173 -0
- librelane/scripts/odbpy/snap_to_grid.py +57 -0
- librelane/scripts/odbpy/wire_lengths.py +93 -0
- librelane/scripts/openroad/antenna_check.tcl +20 -0
- librelane/scripts/openroad/antenna_repair.tcl +31 -0
- librelane/scripts/openroad/basic_mp.tcl +24 -0
- librelane/scripts/openroad/buffer_list.tcl +10 -0
- librelane/scripts/openroad/common/dpl.tcl +24 -0
- librelane/scripts/openroad/common/dpl_cell_pad.tcl +26 -0
- librelane/scripts/openroad/common/grt.tcl +32 -0
- librelane/scripts/openroad/common/io.tcl +540 -0
- librelane/scripts/openroad/common/pdn_cfg.tcl +135 -0
- librelane/scripts/openroad/common/resizer.tcl +103 -0
- librelane/scripts/openroad/common/set_global_connections.tcl +78 -0
- librelane/scripts/openroad/common/set_layer_adjustments.tcl +31 -0
- librelane/scripts/openroad/common/set_power_nets.tcl +30 -0
- librelane/scripts/openroad/common/set_rc.tcl +75 -0
- librelane/scripts/openroad/common/set_routing_layers.tcl +30 -0
- librelane/scripts/openroad/cts.tcl +80 -0
- librelane/scripts/openroad/cut_rows.tcl +24 -0
- librelane/scripts/openroad/dpl.tcl +24 -0
- librelane/scripts/openroad/drt.tcl +37 -0
- librelane/scripts/openroad/fill.tcl +30 -0
- librelane/scripts/openroad/floorplan.tcl +145 -0
- librelane/scripts/openroad/gpl.tcl +88 -0
- librelane/scripts/openroad/grt.tcl +30 -0
- librelane/scripts/openroad/gui.tcl +37 -0
- librelane/scripts/openroad/insert_buffer.tcl +127 -0
- librelane/scripts/openroad/ioplacer.tcl +67 -0
- librelane/scripts/openroad/irdrop.tcl +51 -0
- librelane/scripts/openroad/pdn.tcl +52 -0
- librelane/scripts/openroad/rcx.tcl +32 -0
- librelane/scripts/openroad/repair_design.tcl +70 -0
- librelane/scripts/openroad/repair_design_postgrt.tcl +48 -0
- librelane/scripts/openroad/rsz_timing_postcts.tcl +68 -0
- librelane/scripts/openroad/rsz_timing_postgrt.tcl +70 -0
- librelane/scripts/openroad/sta/check_macro_instances.tcl +53 -0
- librelane/scripts/openroad/sta/corner.tcl +393 -0
- librelane/scripts/openroad/tapcell.tcl +25 -0
- librelane/scripts/openroad/write_views.tcl +27 -0
- librelane/scripts/pyosys/construct_abc_script.py +177 -0
- librelane/scripts/pyosys/json_header.py +84 -0
- librelane/scripts/pyosys/synthesize.py +493 -0
- librelane/scripts/pyosys/ys_common.py +153 -0
- librelane/scripts/tclsh/hello.tcl +1 -0
- librelane/state/__init__.py +24 -0
- librelane/state/__main__.py +61 -0
- librelane/state/design_format.py +195 -0
- librelane/state/state.py +359 -0
- librelane/steps/__init__.py +61 -0
- librelane/steps/__main__.py +510 -0
- librelane/steps/checker.py +637 -0
- librelane/steps/common_variables.py +340 -0
- librelane/steps/cvc_rv.py +169 -0
- librelane/steps/klayout.py +509 -0
- librelane/steps/magic.py +576 -0
- librelane/steps/misc.py +160 -0
- librelane/steps/netgen.py +253 -0
- librelane/steps/odb.py +1088 -0
- librelane/steps/openroad.py +2460 -0
- librelane/steps/openroad_alerts.py +102 -0
- librelane/steps/pyosys.py +640 -0
- librelane/steps/step.py +1571 -0
- librelane/steps/tclstep.py +288 -0
- librelane/steps/verilator.py +222 -0
- librelane/steps/yosys.py +371 -0
- librelane-2.4.0.dist-info/METADATA +169 -0
- librelane-2.4.0.dist-info/RECORD +170 -0
- librelane-2.4.0.dist-info/WHEEL +4 -0
- 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()
|