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,84 @@
|
|
|
1
|
+
# Copyright 2020-2024 Efabless Corporation
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
import json
|
|
15
|
+
|
|
16
|
+
import click
|
|
17
|
+
|
|
18
|
+
from ys_common import ys
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@click.command()
|
|
22
|
+
@click.option("--output", type=click.Path(exists=False, dir_okay=False), required=True)
|
|
23
|
+
@click.option(
|
|
24
|
+
"--config-in", type=click.Path(exists=True, dir_okay=False), required=True
|
|
25
|
+
)
|
|
26
|
+
@click.option("--extra-in", type=click.Path(exists=True, dir_okay=False), required=True)
|
|
27
|
+
def json_header(
|
|
28
|
+
output,
|
|
29
|
+
config_in,
|
|
30
|
+
extra_in,
|
|
31
|
+
):
|
|
32
|
+
config = json.load(open(config_in))
|
|
33
|
+
extra = json.load(open(extra_in))
|
|
34
|
+
|
|
35
|
+
blackbox_models = extra["blackbox_models"]
|
|
36
|
+
|
|
37
|
+
includes = config["VERILOG_INCLUDE_DIRS"] or []
|
|
38
|
+
defines = (
|
|
39
|
+
(config["VERILOG_DEFINES"] or [])
|
|
40
|
+
+ [
|
|
41
|
+
f"PDK_{config['PDK']}",
|
|
42
|
+
f"SCL_{config['STD_CELL_LIBRARY']}",
|
|
43
|
+
"__librelane__",
|
|
44
|
+
"__pnr__",
|
|
45
|
+
]
|
|
46
|
+
+ (
|
|
47
|
+
[]
|
|
48
|
+
if config.get("VERILOG_POWER_DEFINE") is None
|
|
49
|
+
else [config.get("VERILOG_POWER_DEFINE")]
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
d = ys.Design()
|
|
54
|
+
d.add_blackbox_models(
|
|
55
|
+
blackbox_models,
|
|
56
|
+
includes=includes,
|
|
57
|
+
defines=defines,
|
|
58
|
+
)
|
|
59
|
+
d.read_verilog_files(
|
|
60
|
+
config["VERILOG_FILES"],
|
|
61
|
+
top=config["DESIGN_NAME"],
|
|
62
|
+
synth_parameters=config["SYNTH_PARAMETERS"] or [],
|
|
63
|
+
includes=includes,
|
|
64
|
+
defines=defines,
|
|
65
|
+
use_synlig=config["USE_SYNLIG"],
|
|
66
|
+
synlig_defer=config["SYNLIG_DEFER"],
|
|
67
|
+
)
|
|
68
|
+
d.run_pass(
|
|
69
|
+
"hierarchy",
|
|
70
|
+
"-check",
|
|
71
|
+
"-top",
|
|
72
|
+
config["DESIGN_NAME"],
|
|
73
|
+
"-nokeep_prints",
|
|
74
|
+
"-nokeep_asserts",
|
|
75
|
+
)
|
|
76
|
+
d.run_pass("rename", "-top", config["DESIGN_NAME"])
|
|
77
|
+
d.run_pass("proc")
|
|
78
|
+
d.run_pass("flatten")
|
|
79
|
+
d.run_pass("opt_clean", "-purge")
|
|
80
|
+
d.run_pass("json", "-o", output)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__":
|
|
84
|
+
json_header()
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Copyright 2020-2024 Efabless Corporation
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# Parts of this file adapted from:
|
|
16
|
+
#
|
|
17
|
+
# * https://github.com/YosysHQ/yosys/blob/master/techlibs/common/synth.cc
|
|
18
|
+
# * https://github.com/YosysHQ/yosys/blob/master/passes/opt/opt.cc
|
|
19
|
+
#
|
|
20
|
+
# Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
|
|
21
|
+
#
|
|
22
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
|
23
|
+
# purpose with or without fee is hereby granted, provided that the above
|
|
24
|
+
# copyright notice and this permission notice appear in all copies.
|
|
25
|
+
#
|
|
26
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
27
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
28
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
29
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
30
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
31
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
32
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
33
|
+
|
|
34
|
+
import os
|
|
35
|
+
import json
|
|
36
|
+
import shutil
|
|
37
|
+
|
|
38
|
+
import click
|
|
39
|
+
|
|
40
|
+
from ys_common import ys
|
|
41
|
+
from construct_abc_script import ABCScriptCreator
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def librelane_proc(d: ys.Design, report_dir: str):
|
|
45
|
+
d.run_pass("proc_clean") # Clean up unused procedures
|
|
46
|
+
d.run_pass("proc_rmdead") # Remove dead procedures
|
|
47
|
+
d.run_pass("proc_prune") # Prune unused parts of procedures
|
|
48
|
+
d.run_pass("proc_init") # Initialize procedures
|
|
49
|
+
d.run_pass("proc_arst") # Analyze reset signals in procedures
|
|
50
|
+
d.run_pass("proc_rom") # Map ROMs within procedures
|
|
51
|
+
d.run_pass("proc_mux") # Optimize multiplexers within procedures
|
|
52
|
+
d.tee(
|
|
53
|
+
"proc_dlatch", o=os.path.join(report_dir, "latch.rpt")
|
|
54
|
+
) # Report latches after procedure processing
|
|
55
|
+
d.run_pass("proc_dff") # Analyze flip-flops within procedures
|
|
56
|
+
d.run_pass("proc_memwr") # Analyze memory writes within procedures
|
|
57
|
+
d.run_pass("proc_clean") # Clean up after procedure processing
|
|
58
|
+
d.tee("check", o=os.path.join(report_dir, "pre_synth_chk.rpt"))
|
|
59
|
+
d.run_pass("opt_expr") # Optimize expressions
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def librelane_opt(
|
|
63
|
+
d,
|
|
64
|
+
fast=False,
|
|
65
|
+
mux_undef=False,
|
|
66
|
+
mux_bool=False,
|
|
67
|
+
undriven=False,
|
|
68
|
+
fine=False,
|
|
69
|
+
purge=False,
|
|
70
|
+
noclkinv=False,
|
|
71
|
+
keepdc=False,
|
|
72
|
+
share_all=False,
|
|
73
|
+
nodffe=False,
|
|
74
|
+
nosdff=False,
|
|
75
|
+
sat=False,
|
|
76
|
+
opt_share=False,
|
|
77
|
+
noff=False,
|
|
78
|
+
):
|
|
79
|
+
expr_args = []
|
|
80
|
+
merge_args = []
|
|
81
|
+
reduce_args = []
|
|
82
|
+
clean_args = []
|
|
83
|
+
dff_args = []
|
|
84
|
+
if purge:
|
|
85
|
+
clean_args.append("-purge")
|
|
86
|
+
if mux_undef:
|
|
87
|
+
expr_args.append("-mux_undef")
|
|
88
|
+
if mux_bool:
|
|
89
|
+
expr_args.append("-mux_bool")
|
|
90
|
+
if undriven:
|
|
91
|
+
expr_args.append("-undriven")
|
|
92
|
+
if fine:
|
|
93
|
+
expr_args.append("-fine")
|
|
94
|
+
reduce_args.append("-fine")
|
|
95
|
+
if noclkinv:
|
|
96
|
+
expr_args.append("-noclkinv")
|
|
97
|
+
if keepdc:
|
|
98
|
+
expr_args.append("-keepdc")
|
|
99
|
+
dff_args.append("-keepdc")
|
|
100
|
+
merge_args.append("-keepdc")
|
|
101
|
+
if nodffe:
|
|
102
|
+
dff_args.append("-nodffe")
|
|
103
|
+
if nosdff:
|
|
104
|
+
dff_args.append("-nosdff")
|
|
105
|
+
if sat:
|
|
106
|
+
dff_args.append("-sat")
|
|
107
|
+
if share_all:
|
|
108
|
+
merge_args.append("-share_all")
|
|
109
|
+
if fast:
|
|
110
|
+
while True:
|
|
111
|
+
d.run_pass("opt_expr", *expr_args)
|
|
112
|
+
d.run_pass("opt_merge", *merge_args)
|
|
113
|
+
d.scratchpad_unset("opt.did_something")
|
|
114
|
+
if not noff:
|
|
115
|
+
d.run_pass("opt_dff", *dff_args)
|
|
116
|
+
if not d.scratchpad_get_bool("opt.did_something"):
|
|
117
|
+
break
|
|
118
|
+
d.run_pass("opt_clean", *clean_args)
|
|
119
|
+
ys.log_header(d, "Rerunning OPT passes (Removed registers in this run.)")
|
|
120
|
+
d.run_pass("opt_clean", *clean_args)
|
|
121
|
+
else:
|
|
122
|
+
d.run_pass("opt_expr", *expr_args)
|
|
123
|
+
d.run_pass("opt_merge", "-nomux", *merge_args)
|
|
124
|
+
while True:
|
|
125
|
+
d.scratchpad_unset("opt.did_something")
|
|
126
|
+
d.run_pass("opt_muxtree")
|
|
127
|
+
d.run_pass("opt_reduce", *reduce_args)
|
|
128
|
+
d.run_pass("opt_merge", *merge_args)
|
|
129
|
+
if opt_share:
|
|
130
|
+
d.run_pass("opt_share")
|
|
131
|
+
if not noff:
|
|
132
|
+
d.run_pass("opt_dff", *dff_args)
|
|
133
|
+
d.run_pass("opt_clean", *clean_args)
|
|
134
|
+
d.run_pass("opt_expr", *expr_args)
|
|
135
|
+
if not d.scratchpad_get_bool("opt.did_something"):
|
|
136
|
+
break
|
|
137
|
+
ys.log_header(d, "Rerunning OPT passes. (Maybe there is more to do…)")
|
|
138
|
+
|
|
139
|
+
d.optimize()
|
|
140
|
+
d.sort()
|
|
141
|
+
d.check()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def librelane_synth(
|
|
145
|
+
d, top, flatten, report_dir, *, booth=False, abc_dff=False, undriven=True
|
|
146
|
+
):
|
|
147
|
+
d.run_pass("hierarchy", "-check", "-top", top, "-nokeep_prints", "-nokeep_asserts")
|
|
148
|
+
librelane_proc(d, report_dir)
|
|
149
|
+
|
|
150
|
+
if flatten:
|
|
151
|
+
d.run_pass("flatten") # Flatten the design hierarchy
|
|
152
|
+
|
|
153
|
+
d.run_pass("opt_expr") # Optimize expressions again
|
|
154
|
+
|
|
155
|
+
d.run_pass("opt_clean") # Clean up after optimization
|
|
156
|
+
|
|
157
|
+
# Perform various logic optimization passes
|
|
158
|
+
librelane_opt(d, nodffe=True, nosdff=True)
|
|
159
|
+
d.run_pass("fsm") # Identify and optimize finite state machines
|
|
160
|
+
librelane_opt(d)
|
|
161
|
+
d.run_pass("wreduce") # Reduce logic using algebraic rewriting
|
|
162
|
+
d.run_pass("peepopt") # Perform local peephole optimization
|
|
163
|
+
d.run_pass("opt_clean") # Clean up after optimization
|
|
164
|
+
if booth:
|
|
165
|
+
d.run_pass("booth")
|
|
166
|
+
d.run_pass("alumacc") # Optimize arithmetic logic unitsb
|
|
167
|
+
d.run_pass("share") # Share logic across the design
|
|
168
|
+
librelane_opt(d)
|
|
169
|
+
|
|
170
|
+
# Memory optimization
|
|
171
|
+
d.run_pass("memory", "-nomap") # Analyze memories but don't map them yet
|
|
172
|
+
d.run_pass("opt_clean") # Clean up after memory analysis
|
|
173
|
+
|
|
174
|
+
# Perform more aggressive optimization with faster runtime
|
|
175
|
+
librelane_opt(
|
|
176
|
+
d,
|
|
177
|
+
fast=True,
|
|
178
|
+
opt_share=True, # affects opt_share
|
|
179
|
+
mux_undef=True, # affects opt_expr
|
|
180
|
+
mux_bool=True, # affects opt_expr
|
|
181
|
+
undriven=undriven, # affects opt_expr
|
|
182
|
+
fine=True, # affects opt_expr, opt_reduce
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Technology mapping
|
|
186
|
+
d.run_pass("memory_map") # Map memories to standard cells
|
|
187
|
+
librelane_opt(
|
|
188
|
+
d,
|
|
189
|
+
opt_share=True, # affects opt_share
|
|
190
|
+
mux_undef=True, # affects opt_expr
|
|
191
|
+
mux_bool=True, # affects opt_expr
|
|
192
|
+
undriven=undriven, # affects opt_expr
|
|
193
|
+
fine=True, # affects opt_expr, opt_reduce
|
|
194
|
+
)
|
|
195
|
+
d.run_pass("techmap")
|
|
196
|
+
|
|
197
|
+
# Couple more fast opt iterations
|
|
198
|
+
librelane_opt(d, fast=True)
|
|
199
|
+
librelane_opt(d, fast=True)
|
|
200
|
+
|
|
201
|
+
d.run_pass(
|
|
202
|
+
"abc", "-fast", *(["-dff"] if abc_dff else [])
|
|
203
|
+
) # Run ABC with fast settings
|
|
204
|
+
d.run_pass("opt", "-fast") # MORE fast optimization
|
|
205
|
+
|
|
206
|
+
# Checks and Stats
|
|
207
|
+
d.run_pass("hierarchy", "-check", "-top", top, "-nokeep_prints", "-nokeep_asserts")
|
|
208
|
+
d.run_pass("check")
|
|
209
|
+
d.run_pass("stat")
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@click.command()
|
|
213
|
+
@click.option("--output", type=click.Path(exists=False, dir_okay=False), required=True)
|
|
214
|
+
@click.option("--config-in", type=click.Path(exists=True), required=True)
|
|
215
|
+
@click.option("--extra-in", type=click.Path(exists=True), required=True)
|
|
216
|
+
@click.option("--lighter-dff-map", type=click.Path(exists=True), required=False)
|
|
217
|
+
@click.argument("inputs", nargs=-1)
|
|
218
|
+
def synthesize(
|
|
219
|
+
output,
|
|
220
|
+
config_in,
|
|
221
|
+
extra_in,
|
|
222
|
+
lighter_dff_map,
|
|
223
|
+
inputs,
|
|
224
|
+
):
|
|
225
|
+
config = json.load(open(config_in))
|
|
226
|
+
extra = json.load(open(extra_in))
|
|
227
|
+
|
|
228
|
+
includes = config.get("VERILOG_INCLUDE_DIRS") or []
|
|
229
|
+
defines = (config.get("VERILOG_DEFINES") or []) + [
|
|
230
|
+
f"PDK_{config['PDK']}",
|
|
231
|
+
f"SCL_{config['STD_CELL_LIBRARY']}",
|
|
232
|
+
"__librelane__",
|
|
233
|
+
"__pnr__",
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
blackbox_models = extra["blackbox_models"]
|
|
237
|
+
libs = extra["libs_synth"]
|
|
238
|
+
|
|
239
|
+
d = ys.Design()
|
|
240
|
+
|
|
241
|
+
step_dir = os.path.dirname(output)
|
|
242
|
+
report_dir = os.path.join(step_dir, "reports")
|
|
243
|
+
os.makedirs(report_dir, exist_ok=True)
|
|
244
|
+
|
|
245
|
+
d.add_blackbox_models(blackbox_models, includes=includes, defines=defines)
|
|
246
|
+
|
|
247
|
+
clock_period = config["CLOCK_PERIOD"] * 1000 # ns -> ps
|
|
248
|
+
|
|
249
|
+
# ABC only supports these two:
|
|
250
|
+
# https://github.com/YosysHQ/abc/blob/28d955ca97a1c4be3aed4062aec0241a734fac5d/src/map/scl/sclUtil.c#L257
|
|
251
|
+
sdc_path = os.path.join(step_dir, "synthesis.abc.sdc")
|
|
252
|
+
with open(sdc_path, "w") as f:
|
|
253
|
+
print(f"set_driving_cell {config['SYNTH_DRIVING_CELL']}", file=f)
|
|
254
|
+
print(f"set_load {config['OUTPUT_CAP_LOAD']}", file=f)
|
|
255
|
+
|
|
256
|
+
ys.log(f"[INFO] Using SDC file '{sdc_path}' for ABC…")
|
|
257
|
+
|
|
258
|
+
if len(inputs):
|
|
259
|
+
d.read_verilog_files(
|
|
260
|
+
inputs,
|
|
261
|
+
top=config["DESIGN_NAME"],
|
|
262
|
+
synth_parameters=[],
|
|
263
|
+
includes=includes,
|
|
264
|
+
defines=defines,
|
|
265
|
+
use_synlig=False,
|
|
266
|
+
synlig_defer=False,
|
|
267
|
+
)
|
|
268
|
+
elif verilog_files := config.get("VERILOG_FILES"):
|
|
269
|
+
d.read_verilog_files(
|
|
270
|
+
verilog_files,
|
|
271
|
+
top=config["DESIGN_NAME"],
|
|
272
|
+
synth_parameters=config["SYNTH_PARAMETERS"] or [],
|
|
273
|
+
includes=includes,
|
|
274
|
+
defines=defines,
|
|
275
|
+
use_synlig=config["USE_SYNLIG"],
|
|
276
|
+
synlig_defer=config["SYNLIG_DEFER"],
|
|
277
|
+
)
|
|
278
|
+
elif vhdl_files := config.get("VHDL_FILES"):
|
|
279
|
+
d.run_pass("plugin", "-i", "ghdl")
|
|
280
|
+
d.run_pass("ghdl", *vhdl_files, "-e", config["DESIGN_NAME"])
|
|
281
|
+
else:
|
|
282
|
+
ys.log_error(
|
|
283
|
+
"Script called inappropriately: config must include either VERILOG_FILES or VHDL_FILES.",
|
|
284
|
+
)
|
|
285
|
+
exit(1)
|
|
286
|
+
|
|
287
|
+
d.run_pass(
|
|
288
|
+
"hierarchy",
|
|
289
|
+
"-check",
|
|
290
|
+
"-top",
|
|
291
|
+
config["DESIGN_NAME"],
|
|
292
|
+
"-nokeep_prints",
|
|
293
|
+
"-nokeep_asserts",
|
|
294
|
+
)
|
|
295
|
+
d.run_pass("rename", "-top", config["DESIGN_NAME"])
|
|
296
|
+
d.run_pass("select", "-module", config["DESIGN_NAME"])
|
|
297
|
+
try:
|
|
298
|
+
d.run_pass(
|
|
299
|
+
"show", "-format", "dot", "-prefix", os.path.join(step_dir, "hierarchy")
|
|
300
|
+
)
|
|
301
|
+
except Exception:
|
|
302
|
+
pass
|
|
303
|
+
d.run_pass("select", "-clear")
|
|
304
|
+
|
|
305
|
+
lib_arguments = []
|
|
306
|
+
for lib in libs:
|
|
307
|
+
lib_arguments.extend(["-liberty", lib])
|
|
308
|
+
|
|
309
|
+
if config["SYNTH_ELABORATE_ONLY"]:
|
|
310
|
+
librelane_proc(d, report_dir)
|
|
311
|
+
if config["SYNTH_ELABORATE_FLATTEN"]:
|
|
312
|
+
d.run_pass("flatten", "-noscopeinfo")
|
|
313
|
+
d.run_pass("setattr", "-set", "keep", "1")
|
|
314
|
+
d.run_pass("splitnets")
|
|
315
|
+
d.run_pass("opt_clean", "-purge")
|
|
316
|
+
d.tee("check", o=os.path.join(report_dir, "chk.rpt"))
|
|
317
|
+
d.tee("stat", "-json", *lib_arguments, o=os.path.join(report_dir, "stat.json"))
|
|
318
|
+
d.tee("stat", *lib_arguments, o=os.path.join(report_dir, "stat.rpt"))
|
|
319
|
+
|
|
320
|
+
noattr_flag = []
|
|
321
|
+
if config["SYNTH_WRITE_NOATTR"]:
|
|
322
|
+
noattr_flag.append("-noattr")
|
|
323
|
+
|
|
324
|
+
d.run_pass(
|
|
325
|
+
"write_verilog",
|
|
326
|
+
*noattr_flag,
|
|
327
|
+
"-nohex",
|
|
328
|
+
"-nodec",
|
|
329
|
+
"-defparam",
|
|
330
|
+
output,
|
|
331
|
+
)
|
|
332
|
+
d.run_pass("write_json", f"{output}.json")
|
|
333
|
+
exit(0)
|
|
334
|
+
|
|
335
|
+
if config["SYNTH_TRISTATE_MAP"] is not None:
|
|
336
|
+
d.run_pass("tribuf")
|
|
337
|
+
|
|
338
|
+
adder_type = config["SYNTH_ADDER_TYPE"]
|
|
339
|
+
if adder_type not in ["YOSYS", "FA"]:
|
|
340
|
+
if mapping := config[f"SYNTH_{adder_type}_MAP"]:
|
|
341
|
+
ys.log(f"[INFO] Applying {adder_type} mapping from '{mapping}'…")
|
|
342
|
+
d.run_pass("techmap", "-map", mapping)
|
|
343
|
+
|
|
344
|
+
if mapping := lighter_dff_map:
|
|
345
|
+
ys.log(f"[INFO] Using Lighter with mapping '{mapping}'…")
|
|
346
|
+
d.run_pass("plugin", "-i", "lighter")
|
|
347
|
+
d.run_pass("reg_clock_gating", "-map", mapping)
|
|
348
|
+
|
|
349
|
+
librelane_synth(
|
|
350
|
+
d,
|
|
351
|
+
config["DESIGN_NAME"],
|
|
352
|
+
config["SYNTH_HIERARCHY_MODE"] == "flatten",
|
|
353
|
+
report_dir,
|
|
354
|
+
booth=config["SYNTH_MUL_BOOTH"],
|
|
355
|
+
abc_dff=config["SYNTH_ABC_DFF"],
|
|
356
|
+
undriven=config.get("SYNTH_TIE_UNDEFINED") is not None,
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
d.run_pass("delete", "t:$print")
|
|
360
|
+
d.run_pass("delete", "t:$assert")
|
|
361
|
+
|
|
362
|
+
try:
|
|
363
|
+
d.run_pass(
|
|
364
|
+
"show",
|
|
365
|
+
"-format",
|
|
366
|
+
"dot",
|
|
367
|
+
"-prefix",
|
|
368
|
+
os.path.join(step_dir, "primitive_techmap"),
|
|
369
|
+
)
|
|
370
|
+
except Exception:
|
|
371
|
+
pass
|
|
372
|
+
|
|
373
|
+
d.run_pass("opt")
|
|
374
|
+
d.run_pass("opt_clean", "-purge")
|
|
375
|
+
|
|
376
|
+
d.tee(
|
|
377
|
+
"stat", "-json", *lib_arguments, o=os.path.join(report_dir, "pre_techmap.json")
|
|
378
|
+
)
|
|
379
|
+
d.tee("stat", *lib_arguments, o=os.path.join(report_dir, "pre_techmap.rpt"))
|
|
380
|
+
|
|
381
|
+
if tristate_mapping := config["SYNTH_TRISTATE_MAP"]:
|
|
382
|
+
ys.log(f"[INFO] Applying tri-state buffer mapping from '{tristate_mapping}'…")
|
|
383
|
+
d.run_pass("techmap", "-map", tristate_mapping)
|
|
384
|
+
d.run_pass("simplemap")
|
|
385
|
+
if fa_mapping := config["SYNTH_FA_MAP"]:
|
|
386
|
+
if adder_type == "FA":
|
|
387
|
+
ys.log(f"[INFO] Applying full-adder mapping from '{fa_mapping}'…")
|
|
388
|
+
d.run_pass("techmap", "-map", fa_mapping)
|
|
389
|
+
if latch_mapping := config["SYNTH_LATCH_MAP"]:
|
|
390
|
+
ys.log(f"[INFO] Applying latch mapping from '{latch_mapping}'…")
|
|
391
|
+
d.run_pass("techmap", "-map", latch_mapping)
|
|
392
|
+
d.run_pass("simplemap")
|
|
393
|
+
if extra_mapping := config["SYNTH_EXTRA_MAPPING_FILE"]:
|
|
394
|
+
ys.log(f"[INFO] Applying extra mappings from '{extra_mapping}'…")
|
|
395
|
+
d.run_pass("techmap", "-map", extra_mapping)
|
|
396
|
+
|
|
397
|
+
dfflibmap_args = []
|
|
398
|
+
for lib in libs:
|
|
399
|
+
dfflibmap_args.extend(["-liberty", lib])
|
|
400
|
+
d.run_pass("dfflibmap", *dfflibmap_args)
|
|
401
|
+
|
|
402
|
+
d.tee("stat", "-json", *lib_arguments, o=os.path.join(report_dir, "post_dff.json"))
|
|
403
|
+
d.tee("stat", *lib_arguments, o=os.path.join(report_dir, "post_dff.rpt"))
|
|
404
|
+
|
|
405
|
+
script_creator = ABCScriptCreator(config)
|
|
406
|
+
|
|
407
|
+
def run_strategy(d):
|
|
408
|
+
abc_script = script_creator.generate_abc_script(
|
|
409
|
+
step_dir,
|
|
410
|
+
config["SYNTH_STRATEGY"],
|
|
411
|
+
)
|
|
412
|
+
ys.log(f"[INFO] Using generated ABC script '{abc_script}'…")
|
|
413
|
+
d.run_pass(
|
|
414
|
+
"abc",
|
|
415
|
+
"-script",
|
|
416
|
+
abc_script,
|
|
417
|
+
"-D",
|
|
418
|
+
f"{clock_period}",
|
|
419
|
+
"-constr",
|
|
420
|
+
sdc_path,
|
|
421
|
+
"-showtmp",
|
|
422
|
+
*lib_arguments,
|
|
423
|
+
*(["-dff"] if config["SYNTH_ABC_DFF"] else []),
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
if value := config.get("SYNTH_TIE_UNDEFINED"):
|
|
427
|
+
flag = "-zero" if value == "low" else "-one"
|
|
428
|
+
d.run_pass("setundef", flag)
|
|
429
|
+
|
|
430
|
+
d.run_pass(
|
|
431
|
+
"hilomap",
|
|
432
|
+
"-hicell",
|
|
433
|
+
*config["SYNTH_TIEHI_CELL"].split("/"),
|
|
434
|
+
"-locell",
|
|
435
|
+
*config["SYNTH_TIELO_CELL"].split("/"),
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
if config["SYNTH_SPLITNETS"]:
|
|
439
|
+
d.run_pass("splitnets")
|
|
440
|
+
d.run_pass("opt_clean", "-purge")
|
|
441
|
+
|
|
442
|
+
if config["SYNTH_DIRECT_WIRE_BUFFERING"]:
|
|
443
|
+
d.run_pass("insbuf", "-buf", *config["SYNTH_BUFFER_CELL"].split("/"))
|
|
444
|
+
|
|
445
|
+
d.tee("check", o=os.path.join(report_dir, "chk.rpt"))
|
|
446
|
+
d.tee("stat", "-json", *lib_arguments, o=os.path.join(report_dir, "stat.json"))
|
|
447
|
+
d.tee("stat", *lib_arguments, o=os.path.join(report_dir, "stat.rpt"))
|
|
448
|
+
|
|
449
|
+
if config["SYNTH_AUTONAME"]:
|
|
450
|
+
# Generate public names for the various nets, resulting in very long
|
|
451
|
+
# names that include the full hierarchy, which is preferable to the
|
|
452
|
+
# internal names that are simply sequential numbers such as `_000019_`.
|
|
453
|
+
# Renamed net names can be very long, such as:
|
|
454
|
+
# manual_reset_gf180mcu_fd_sc_mcu7t5v0__dffq_1_Q_D_gf180mcu_ \
|
|
455
|
+
# fd_sc_mcu7t5v0__nor3_1_ZN_A1_gf180mcu_fd_sc_mcu7t5v0__aoi21_ \
|
|
456
|
+
# 1_A2_A1_gf180mcu_fd_sc_mcu7t5v0__nand3_1_ZN_A3_gf180mcu_fd_ \
|
|
457
|
+
# sc_mcu7t5v0__and3_1_A3_Z_gf180mcu_fd_sc_mcu7t5v0__buf_1_I_Z
|
|
458
|
+
d.run_pass("autoname")
|
|
459
|
+
|
|
460
|
+
noattr_flag = []
|
|
461
|
+
if config["SYNTH_WRITE_NOATTR"]:
|
|
462
|
+
noattr_flag.append("-noattr")
|
|
463
|
+
|
|
464
|
+
d.run_pass(
|
|
465
|
+
"write_verilog",
|
|
466
|
+
*noattr_flag,
|
|
467
|
+
"-noexpr",
|
|
468
|
+
"-nohex",
|
|
469
|
+
"-nodec",
|
|
470
|
+
"-defparam",
|
|
471
|
+
output,
|
|
472
|
+
)
|
|
473
|
+
d.run_pass("write_json", f"{output}.json")
|
|
474
|
+
|
|
475
|
+
run_strategy(d)
|
|
476
|
+
|
|
477
|
+
if config["SYNTH_HIERARCHY_MODE"] == "deferred_flatten":
|
|
478
|
+
# Resynthesize, flattening
|
|
479
|
+
d_flat = ys.Design()
|
|
480
|
+
d_flat.add_blackbox_models(blackbox_models, includes=includes, defines=defines)
|
|
481
|
+
|
|
482
|
+
shutil.copy(output, f"{output}.hierarchy.nl.v")
|
|
483
|
+
d_flat.run_pass("read_verilog", "-sv", output)
|
|
484
|
+
d_flat.run_pass(
|
|
485
|
+
"synth",
|
|
486
|
+
"-flatten",
|
|
487
|
+
*(["-booth"] if config["SYNTH_MUL_BOOTH"] else []),
|
|
488
|
+
)
|
|
489
|
+
run_strategy(d_flat)
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
if __name__ == "__main__":
|
|
493
|
+
synthesize()
|