librelane 2.4.0.dev0__py3-none-any.whl → 2.4.0.dev3__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.

@@ -131,16 +131,9 @@ class OdbReader(object):
131
131
  dpl.reportLegalizationStats()
132
132
  dpl.optimizeMirroring()
133
133
 
134
- def _grt(self):
135
- """
136
- The ``._grt()`` method is EXPERIMENTAL and SHOULD NOT BE USED YET.
137
-
138
- Use a composite step with ``OpenROAD.GlobalRouting``.
139
- """
140
- if self.config is None:
141
- raise RuntimeError("Attempted to call grt without config file")
134
+ def _grt_setup(self, grt):
135
+ grt.setAdjustment(float(self.config["GRT_ADJUSTMENT"]))
142
136
 
143
- grt = self.design.getGlobalRouter()
144
137
  routing_layers = [l for l in self.layers.values() if l.getRoutingLevel() >= 1]
145
138
  for layer, adj in zip(routing_layers, self.config["GRT_LAYER_ADJUSTMENTS"]):
146
139
  grt.addLayerAdjustment(
@@ -170,14 +163,25 @@ class OdbReader(object):
170
163
  raise RuntimeError(f"Unknown layer name '{max_clk_name}'")
171
164
  max_clk_idx = self.layers[max_clk_name].getRoutingLevel()
172
165
 
173
- grt.setMinRoutingLayer(min_layer_idx)
174
- grt.setMaxRoutingLayer(max_layer_idx)
175
166
  grt.setMinLayerForClock(min_clk_idx)
176
167
  grt.setMaxLayerForClock(max_clk_idx)
177
168
  grt.setMacroExtension(self.config["GRT_MACRO_EXTENSION"])
178
169
  grt.setOverflowIterations(self.config["GRT_OVERFLOW_ITERS"])
179
170
  grt.setAllowCongestion(self.config["GRT_ALLOW_CONGESTION"])
180
171
  grt.setVerbose(True)
172
+ grt.initFastRoute(min_layer_idx, max_layer_idx)
173
+
174
+ def _grt(self):
175
+ """
176
+ The ``._grt()`` method is EXPERIMENTAL and SHOULD NOT BE USED YET.
177
+
178
+ Use a composite step with ``OpenROAD.GlobalRouting``.
179
+ """
180
+ if self.config is None:
181
+ raise RuntimeError("Attempted to call grt without config file")
182
+
183
+ grt = self.design.getGlobalRouter()
184
+ self._grt_setup(grt)
181
185
  grt.globalRoute(
182
186
  True
183
187
  ) # The first variable updates guides- not sure why the default is False
@@ -316,6 +316,70 @@ proc read_current_odb {args} {
316
316
  set_dont_use_cells
317
317
  }
318
318
 
319
+ proc _populate_cells_by_class {} {
320
+ if { [info exists ::_cells_by_class(physical)] } {
321
+ return
322
+ }
323
+
324
+ set ::_cells_by_class(physical) [list]
325
+ set ::_cells_by_class(non_timing) [list]
326
+ set _comment_ {
327
+ We naïvely assume anything not in these classes is not a cell with a
328
+ logical function. This may not be comprehensive, but is good enough.
329
+
330
+ CORE just means a macro used in the core area (i.e. a standard cell.)
331
+
332
+ Thing is, it has a lot of subclasses for physical cells:
333
+
334
+ `FEEDTHRU`,`SPACER`,`ANTENNACELL`,`WELLTAP`
335
+
336
+ Only `TIEHIGH`, `TIELOW` are for logical cells. Thus, the inclusion
337
+ list allows them as well. `BLOCKS` are macros, which we cannot discern
338
+ whether they have a logical function or not, so we include them
339
+ regardless.
340
+
341
+ We do make one exception for `ANTENNACELL`s. These are not counted as
342
+ logical cells but they are not exempt from the so-called SDF-friendly
343
+ netlist as they do affect timing ever so slightly.
344
+ }
345
+ set logical_classes {
346
+ BLOCK
347
+ BUMP
348
+ CORE
349
+ CORE_TIEHIGH
350
+ CORE_TIELOW
351
+ COVER
352
+ PAD
353
+ PAD_AREAIO
354
+ PAD_INOUT
355
+ PAD_INPUT
356
+ PAD_OUTPUT
357
+ PAD_POWER
358
+ PAD_SPACER
359
+ }
360
+
361
+ foreach lib $::libs {
362
+ foreach master [$lib getMasters] {
363
+ if { [lsearch -exact $logical_classes [$master getType]] == -1 } {
364
+ lappend ::_cells_by_class(physical) [$master getName]
365
+ if { "[$master getType]" != "CORE_ANTENNACELL" } {
366
+ lappend ::_cells_by_class(non_timing) [$master getName]
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+
373
+ proc get_timing_excluded_cells {args} {
374
+ _populate_cells_by_class
375
+ return $::_cells_by_class(non_timing)
376
+ }
377
+
378
+ proc get_physical_cells {args} {
379
+ _populate_cells_by_class
380
+ return $::_cells_by_class(physical)
381
+ }
382
+
319
383
  proc write_views {args} {
320
384
  # This script will attempt to write views based on existing "SAVE_"
321
385
  # environment variables. If the SAVE_ variable exists, the script will
@@ -349,7 +413,7 @@ proc write_views {args} {
349
413
  }
350
414
 
351
415
  if { [info exists ::env(SAVE_POWERED_NETLIST_SDF_FRIENDLY)] } {
352
- set exclude_cells "[join $::env(FILL_CELL)] [join $::env(DECAP_CELL)] [join $::env(WELLTAP_CELL)] [join $::env(ENDCAP_CELL)]"
416
+ set exclude_cells "[get_timing_excluded_cells]"
353
417
  puts "Writing nofill powered netlist to '$::env(SAVE_POWERED_NETLIST_SDF_FRIENDLY)'…"
354
418
  puts "Excluding $exclude_cells"
355
419
  write_verilog -include_pwr_gnd \
@@ -358,7 +422,7 @@ proc write_views {args} {
358
422
  }
359
423
 
360
424
  if { [info exists ::env(SAVE_POWERED_NETLIST_NO_PHYSICAL_CELLS)] } {
361
- set exclude_cells "[join [lindex [split $::env(DIODE_CELL) "/"] 0]] [join $::env(FILL_CELL)] [join $::env(DECAP_CELL)] [join $::env(WELLTAP_CELL)] [join $::env(ENDCAP_CELL)]"
425
+ set exclude_cells "[get_physical_cells]"
362
426
  puts "Writing nofilldiode powered netlist to '$::env(SAVE_POWERED_NETLIST_NO_PHYSICAL_CELLS)'…"
363
427
  puts "Excluding $exclude_cells"
364
428
  write_verilog -include_pwr_gnd \
@@ -48,7 +48,7 @@ from . import openroad as OpenROAD
48
48
  from .openroad import OpenROADStep
49
49
 
50
50
  from . import odb as Odb
51
- from .odb import OdbpyStep
51
+ from .odb import OdbpyStep, ECOBuffer, ECODiode
52
52
 
53
53
  from . import magic as Magic
54
54
  from .magic import MagicStep
@@ -418,7 +418,7 @@ def create_reproducible(
418
418
  * The current working directory
419
419
 
420
420
  These reproducibles are filesystem-independent, i.e. they can be run
421
- on any computer that has the appropriate version of LibreLane 2 installed
421
+ on any computer that has the appropriate version of LibreLane installed
422
422
  (as well as the underlying utility for that specific step.)
423
423
 
424
424
  The reproducible will report an error if LibreLane is not installed and will
librelane/steps/odb.py CHANGED
@@ -19,28 +19,27 @@ from math import inf
19
19
  from decimal import Decimal
20
20
  from functools import reduce
21
21
  from abc import abstractmethod
22
+ from dataclasses import dataclass
22
23
  from typing import Dict, List, Literal, Optional, Tuple
23
24
 
25
+ from ..common import Path, get_script_dir, aggregate_metrics
26
+ from ..config import Instance, Macro, Variable
27
+ from ..logging import info, verbose
28
+ from ..state import DesignFormat, State
24
29
 
25
- from .common_variables import io_layer_variables
26
- from .openroad_alerts import (
27
- OpenROADAlert,
28
- OpenROADOutputProcessor,
29
- )
30
30
  from .openroad import DetailedPlacement, GlobalRouting
31
- from .tclstep import TclStep
31
+ from .openroad_alerts import OpenROADAlert, OpenROADOutputProcessor
32
+ from .common_variables import io_layer_variables, dpl_variables, grt_variables
32
33
  from .step import (
33
- ViewsUpdate,
34
+ CompositeStep,
35
+ DefaultOutputProcessor,
34
36
  MetricsUpdate,
35
37
  Step,
38
+ StepError,
36
39
  StepException,
37
- CompositeStep,
38
- DefaultOutputProcessor,
40
+ ViewsUpdate,
39
41
  )
40
- from ..logging import info, verbose
41
- from ..config import Variable, Macro, Instance
42
- from ..state import State, DesignFormat
43
- from ..common import Path, get_script_dir
42
+ from .tclstep import TclStep
44
43
 
45
44
  inf_rx = re.compile(r"\b(-?)inf\b")
46
45
 
@@ -51,6 +50,8 @@ class OdbpyStep(Step):
51
50
 
52
51
  output_processors = [OpenROADOutputProcessor, DefaultOutputProcessor]
53
52
 
53
+ alerts: Optional[List[OpenROADAlert]] = None
54
+
54
55
  def on_alert(self, alert: OpenROADAlert) -> OpenROADAlert:
55
56
  if alert.code in [
56
57
  "ORD-0039", # .openroad ignored with -python
@@ -63,7 +64,9 @@ class OdbpyStep(Step):
63
64
  self.warn(str(alert), extra={"key": alert.code})
64
65
  return alert
65
66
 
66
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
67
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
68
+ self.alerts = None
69
+
67
70
  kwargs, env = self.extract_env(kwargs)
68
71
 
69
72
  automatic_outputs = set(self.outputs).intersection(
@@ -86,15 +89,35 @@ class OdbpyStep(Step):
86
89
  env["PYTHONPATH"] = (
87
90
  f'{os.path.join(get_script_dir(), "odbpy")}:{env.get("PYTHONPATH")}'
88
91
  )
92
+ check = False
93
+ if "check" in kwargs:
94
+ check = kwargs.pop("check")
89
95
 
90
96
  subprocess_result = self.run_subprocess(
91
97
  command,
92
98
  env=env,
99
+ check=check,
93
100
  **kwargs,
94
101
  )
102
+ generated_metrics = subprocess_result["generated_metrics"]
95
103
 
104
+ # 1. Parse warnings and errors
105
+ self.alerts = subprocess_result.get("openroad_alerts") or []
106
+ if subprocess_result["returncode"] != 0:
107
+ error_strings = [
108
+ str(alert) for alert in self.alerts if alert.cls == "error"
109
+ ]
110
+ if len(error_strings):
111
+ error_string = "\n".join(error_strings)
112
+ raise StepError(
113
+ f"{self.id} failed with the following errors:\n{error_string}"
114
+ )
115
+ else:
116
+ raise StepException(
117
+ f"{self.id} failed unexpectedly. Please check the logs and file an issue."
118
+ )
119
+ # 2. Metrics
96
120
  metrics_path = os.path.join(self.step_dir, "or_metrics_out.json")
97
- metrics_updates: MetricsUpdate = subprocess_result["generated_metrics"]
98
121
  if os.path.exists(metrics_path):
99
122
  or_metrics_out = json.loads(open(metrics_path).read(), parse_float=Decimal)
100
123
  for key, value in or_metrics_out.items():
@@ -102,9 +125,11 @@ class OdbpyStep(Step):
102
125
  or_metrics_out[key] = inf
103
126
  elif value == "-Infinity":
104
127
  or_metrics_out[key] = -inf
105
- metrics_updates.update(or_metrics_out)
128
+ generated_metrics.update(or_metrics_out)
106
129
 
107
- return views_updates, metrics_updates
130
+ metric_updates_with_aggregates = aggregate_metrics(generated_metrics)
131
+
132
+ return views_updates, metric_updates_with_aggregates
108
133
 
109
134
  def get_command(self) -> List[str]:
110
135
  metrics_path = os.path.join(self.step_dir, "or_metrics_out.json")
@@ -180,7 +205,7 @@ class CheckMacroAntennaProperties(OdbpyStep):
180
205
  args += ["--cell-name", name]
181
206
  return super().get_command() + args
182
207
 
183
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
208
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
184
209
  if not self.get_cells():
185
210
  info("No cells provided, skipping…")
186
211
  return {}, {}
@@ -244,7 +269,7 @@ class ApplyDEFTemplate(OdbpyStep):
244
269
  args.append("--copy-def-power")
245
270
  return super().get_command() + args
246
271
 
247
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
272
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
248
273
  if self.config["FP_DEF_TEMPLATE"] is None:
249
274
  info("No DEF template provided, skipping…")
250
275
  return {}, {}
@@ -339,7 +364,7 @@ class WriteVerilogHeader(OdbpyStep):
339
364
 
340
365
  return command
341
366
 
342
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
367
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
343
368
  views_updates, metrics_updates = super().run(state_in, **kwargs)
344
369
  views_updates[DesignFormat.VERILOG_HEADER] = Path(
345
370
  os.path.join(self.step_dir, f"{self.config['DESIGN_NAME']}.vh")
@@ -528,7 +553,7 @@ class AddRoutingObstructions(OdbpyStep):
528
553
  command.append(obstruction)
529
554
  return command
530
555
 
531
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
556
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
532
557
  if self.config[self.get_obstruction_variable().name] is None:
533
558
  info(
534
559
  f"'{self.get_obstruction_variable().name}' is not defined. Skipping '{self.id}'…"
@@ -659,7 +684,7 @@ class CustomIOPlacement(OdbpyStep):
659
684
  + length_args
660
685
  )
661
686
 
662
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
687
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
663
688
  if self.config["FP_PIN_ORDER_CFG"] is None:
664
689
  info("No custom floorplan file configured, skipping…")
665
690
  return {}, {}
@@ -895,7 +920,7 @@ class CellFrequencyTables(OdbpyStep):
895
920
  def get_buffer_list_script(self):
896
921
  return os.path.join(get_script_dir(), "openroad", "buffer_list.tcl")
897
922
 
898
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
923
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
899
924
  kwargs, env = self.extract_env(kwargs)
900
925
 
901
926
  env_copy = env.copy()
@@ -948,8 +973,119 @@ class ManualGlobalPlacement(OdbpyStep):
948
973
  assert self.config_path is not None, "get_command called before start()"
949
974
  return super().get_command() + ["--step-config", self.config_path]
950
975
 
951
- def run(self, state_in, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
976
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
952
977
  if self.config["MANUAL_GLOBAL_PLACEMENTS"] is None:
953
978
  info("'MANUAL_GLOBAL_PLACEMENTS' not set, skipping…")
954
979
  return {}, {}
955
980
  return super().run(state_in, **kwargs)
981
+
982
+
983
+ @dataclass
984
+ class ECOBuffer:
985
+ """
986
+ :param target: The driver to insert an ECO buffer after or sink to insert an
987
+ ECO buffer before, in the format instance_name/pin_name.
988
+ :param buffer: The kind of buffer cell to use.
989
+ :param placement: The coarse placement for this buffer (to be legalized.)
990
+ If unset, depending on whether the target is a driver or a sink:
991
+
992
+ - Driver: The placement will be the average of the driver and all sinks.
993
+
994
+ - Sink: The placement will be the average of the sink and all drivers.
995
+ """
996
+
997
+ target: str
998
+ buffer: str
999
+ placement: Optional[Tuple[Decimal, Decimal]] = None
1000
+
1001
+
1002
+ @Step.factory.register()
1003
+ class InsertECOBuffers(OdbpyStep):
1004
+ """
1005
+ Experimental step to insert ECO buffers on either drivers or sinks after
1006
+ global or detailed routing. The placement is legalized and global routing is
1007
+ incrementally re-run for affected nets. Useful for manually fixing some hold
1008
+ violations.
1009
+
1010
+ If run after detailed routing, detailed routing must be re-run as affected
1011
+ nets that are altered are removed and require re-routing.
1012
+
1013
+ INOUT and FEEDTHRU ports are not supported.
1014
+ """
1015
+
1016
+ id = "Odb.InsertECOBuffers"
1017
+ name = "Insert ECO Buffers"
1018
+
1019
+ config_vars = (
1020
+ dpl_variables
1021
+ + grt_variables
1022
+ + [
1023
+ Variable(
1024
+ "INSERT_ECO_BUFFERS",
1025
+ Optional[List[ECOBuffer]],
1026
+ "List of buffers to insert",
1027
+ )
1028
+ ]
1029
+ )
1030
+
1031
+ def get_script_path(self):
1032
+ return os.path.join(get_script_dir(), "odbpy", "eco_buffer.py")
1033
+
1034
+ def get_command(self) -> List[str]:
1035
+ assert self.config_path is not None, "get_command called before start()"
1036
+ return super().get_command() + ["--step-config", self.config_path]
1037
+
1038
+
1039
+ @dataclass
1040
+ class ECODiode:
1041
+ """
1042
+ :param target: The sink whose net gets a diode connected, in the format
1043
+ instance_name/pin_name.
1044
+ :param placement: The coarse placement for this diode (to be legalized.)
1045
+ If unset, the diode is placed at the same location as the target
1046
+ instance, with legalization later moving it to a valid location.
1047
+ """
1048
+
1049
+ target: str
1050
+ placement: Optional[Tuple[Decimal, Decimal]] = None
1051
+
1052
+
1053
+ @Step.factory.register()
1054
+ class InsertECODiodes(OdbpyStep):
1055
+ """
1056
+ Experimental step to create and attach ECO diodes to the nets of sinks after
1057
+ global or detailed routing. The placement is legalized and global routing is
1058
+ incrementally re-run for affected nets. Useful for manually fixing some
1059
+ antenna violations.
1060
+
1061
+ If run after detailed routing, detailed routing must be re-run as affected
1062
+ nets that are altered are removed and require re-routing.
1063
+ """
1064
+
1065
+ id = "Odb.InsertECODiodes"
1066
+ name = "Insert ECO Diodes"
1067
+
1068
+ config_vars = (
1069
+ grt_variables
1070
+ + dpl_variables
1071
+ + [
1072
+ Variable(
1073
+ "INSERT_ECO_DIODES",
1074
+ Optional[List[ECODiode]],
1075
+ "List of sinks to insert diodes for.",
1076
+ )
1077
+ ]
1078
+ )
1079
+
1080
+ def get_script_path(self):
1081
+ return os.path.join(get_script_dir(), "odbpy", "eco_diode.py")
1082
+
1083
+ def get_command(self) -> List[str]:
1084
+ assert self.config_path is not None, "get_command called before start()"
1085
+ return super().get_command() + ["--step-config", self.config_path]
1086
+
1087
+ def run(self, state_in: State, **kwargs):
1088
+ if self.config["DIODE_CELL"] is None:
1089
+ info(f"'DIODE_CELL' not set. Skipping '{self.id}'…")
1090
+ return {}, {}
1091
+ return super().run(state_in, **kwargs)
@@ -185,6 +185,8 @@ class OpenROADStep(TclStep):
185
185
 
186
186
  output_processors = [OpenROADOutputProcessor, DefaultOutputProcessor]
187
187
 
188
+ alerts: Optional[List[OpenROADAlert]] = None
189
+
188
190
  config_vars = [
189
191
  Variable(
190
192
  "PDN_CONNECT_MACROS_TO_GRID",
@@ -264,6 +266,7 @@ class OpenROADStep(TclStep):
264
266
  2. After the `super()` call: Processes the `or_metrics_out.json` file and
265
267
  updates the State's `metrics` property with any new metrics in that object.
266
268
  """
269
+ self.alerts = None
267
270
  kwargs, env = self.extract_env(kwargs)
268
271
  env = self.prepare_env(env, state_in)
269
272
 
@@ -293,9 +296,11 @@ class OpenROADStep(TclStep):
293
296
  views_updates[output] = path
294
297
 
295
298
  # 1. Parse warnings and errors
296
- alerts = subprocess_result["openroad_alerts"]
299
+ self.alerts = subprocess_result.get("openroad_alerts") or []
297
300
  if subprocess_result["returncode"] != 0:
298
- error_strings = [str(alert) for alert in alerts if alert.cls == "error"]
301
+ error_strings = [
302
+ str(alert) for alert in self.alerts if alert.cls == "error"
303
+ ]
299
304
  if len(error_strings):
300
305
  error_string = "\n".join(error_strings)
301
306
  raise StepError(
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.1
2
2
  Name: librelane
3
- Version: 2.4.0.dev0
3
+ Version: 2.4.0.dev3
4
4
  Summary: An infrastructure for implementing chip design flows
5
+ Home-page: https://github.com/librelane/librelane
5
6
  License: Apache-2.0
6
7
  Author: Mohamed Gaber
7
8
  Author-email: me@donn.website
@@ -19,8 +20,7 @@ Requires-Dist: click (>=8,<9)
19
20
  Requires-Dist: cloup (>=3.0.5,<4)
20
21
  Requires-Dist: deprecated (>=1.2.10,<2)
21
22
  Requires-Dist: httpx (>=0.22.0,<0.29)
22
- Requires-Dist: ioplace-parser (>=0.3.0,<0.5.0)
23
- Requires-Dist: klayout (>=0.29.0,<0.30.0)
23
+ Requires-Dist: klayout (>=0.29.0,<0.31.0)
24
24
  Requires-Dist: libparse (>=0.3.1,<1)
25
25
  Requires-Dist: lxml (>=4.9.0)
26
26
  Requires-Dist: psutil (>=5.9.0)
@@ -49,8 +49,10 @@ Description-Content-Type: text/markdown
49
49
 
50
50
  LibreLane is an ASIC infrastructure library based on several components including
51
51
  OpenROAD, Yosys, Magic, Netgen, CVC, KLayout and a number of custom scripts for
52
- design exploration and optimization, currently developed and maintained by the
53
- American University in Cairo Open Hardware Lab (AUCOHL.)
52
+ design exploration and optimization, currently developed and maintained by
53
+ members and affiliates of the
54
+ [American University in Cairo Open Hardware Lab](https://github.com/aucohl)
55
+ under the stewardship of the [FOSSi Foundation](https://fossi-foundation.org).
54
56
 
55
57
  A reference flow, "Classic", performs all ASIC implementation steps from RTL all
56
58
  the way down to GDSII.
@@ -142,10 +144,27 @@ If you use LibreLane in your research, please cite the following paper.
142
144
 
143
145
  ## License and Legal Info
144
146
 
145
- LibreLane is a trademark of the FOSSi Foundation.
147
+ LibreLane is a trademark of the [FOSSi Foundation](https://fossi-foundation.org).
146
148
 
149
+ LibreLane code and binaries are available under
147
150
  [The Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt).
148
151
 
149
- LibreLane is based on OpenLane 2.0 by Efabless Corporation
150
- (https://github.com/efabless/openlane2) under the same license.
152
+ LibreLane is based on [OpenLane 2](https://github.com/efabless/openlane2)
153
+ by Efabless Corporation:
154
+
155
+ ```
156
+ Copyright 2022-2025 Efabless Corporation
157
+
158
+ Licensed under the Apache License, Version 2.0 (the "License");
159
+ you may not use this file except in compliance with the License.
160
+ You may obtain a copy of the License at
161
+
162
+ http://www.apache.org/licenses/LICENSE-2.0
163
+
164
+ Unless required by applicable law or agreed to in writing, software
165
+ distributed under the License is distributed on an "AS IS" BASIS,
166
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
167
+ See the License for the specific language governing permissions and
168
+ limitations under the License.
169
+ ```
151
170
 
@@ -1,5 +1,5 @@
1
1
  librelane/__init__.py,sha256=EMpoZrRmS_wsweKjhyAg52OXCK7HWQ8o8CVrYaX4ub0,1220
2
- librelane/__main__.py,sha256=fcJnSzIGqtQMK0jsr5o5bmdH0_i6eiInl6rUl0dZANM,14681
2
+ librelane/__main__.py,sha256=48sW8mh1MNbG0Mf75f5LekXzerbaEASLInQSrvQqPw4,14802
3
3
  librelane/__version__.py,sha256=dbE4stCACDmIoxgKksesAkTa-_hi5dW6nPLWw9Pfq3Q,1486
4
4
  librelane/common/__init__.py,sha256=LrzxjZKJu3-i8oEYdXtV1IxkXicHtoSUNRcOGrGVGsw,1516
5
5
  librelane/common/cli.py,sha256=Ob7mDR77qX1DZ7MXBQ4EPGS3dAO0o7b4njIloOxoB-Q,2351
@@ -18,14 +18,14 @@ librelane/common/tpe.py,sha256=Txj0fVscXSDJTYmEKZ2ESFHOeqrhHnaPPiwWBgyx4g8,1285
18
18
  librelane/common/types.py,sha256=oclAQkeluz_iopI_28clHzxvac7gN5moT8Rzipy5mgM,3468
19
19
  librelane/config/__init__.py,sha256=lbJmD5CbrrrnaNdIUWqFIK488ea0uyej3iExh-9mkgE,1107
20
20
  librelane/config/__main__.py,sha256=6KSXxM4qNE2yJhizUsF1kdMsY1kY7hLHoPoz50POsS8,4532
21
- librelane/config/config.py,sha256=79wDEleGg7Q6dRvbDiOcwN7b3usKUw0xBH3vQDblPHE,34974
21
+ librelane/config/config.py,sha256=WUznKnVYLn7ZNbUL4YMkMX7akmyc2S26ksQSicKeN1c,34964
22
22
  librelane/config/flow.py,sha256=qCGaUOj12j57gORzoE10m7_WG-n600llnFDMlZagUF4,16660
23
23
  librelane/config/pdk_compat.py,sha256=rznq5xIny9M0PmddhPOGtCIrSdv98ysAoYgkpyM0gUA,8450
24
24
  librelane/config/preprocessor.py,sha256=I239Y01dC2o5eb1UtcSbLdybVrZgqGyDr7ecT234I4Y,14913
25
25
  librelane/config/removals.py,sha256=lJ0xpkCqnZAdA_ug4yq0NDjRBFuw4XsdORwymbEVGyQ,2907
26
- librelane/config/variable.py,sha256=NbR4h1Y8h4pFr6ZLUPVTUzpWB9nmlgbD-zb1Z2Ct-ww,26057
27
- librelane/container.py,sha256=nM3sZPlfuUdROn2kInv99bTKpeT9MMQvl4oGteAsmEU,7556
28
- librelane/env_info.py,sha256=p2IyhEILUgcM-zeZaWNHvOya7KPc8_WexVLhhGLoKzM,10462
26
+ librelane/config/variable.py,sha256=tqH7po203Q7usX9jdVoyng2fdKPzDO36UmbCPZcIcsA,26232
27
+ librelane/container.py,sha256=3KHxs3dUSVUZVYsS6fsA7dD3Q4QEQEzRxgXZZh9dzi0,7554
28
+ librelane/env_info.py,sha256=vAE9AZ_vDFLt7Srtg4ZywPzE6vgVhCrIvg8PP25-BJ8,10460
29
29
  librelane/examples/spm/config.yaml,sha256=YKBm0lsY3AJZNcxAh1sQ1QMmJeVCpOpil6dw_RgQh4c,633
30
30
  librelane/examples/spm/pin_order.cfg,sha256=-8mTGFKnES0vhQATfaE2TXN_mdCZ3SZIN90Src1l6fY,52
31
31
  librelane/examples/spm/src/impl.sdc,sha256=wP18UoVlOJ9q4lmUoa3XpgcpPdyzEqHBNxCgOOU7QH0,2961
@@ -41,11 +41,11 @@ librelane/examples/spm-user_project_wrapper/template.def,sha256=7kl9l-oh4BDKuFHh
41
41
  librelane/examples/spm-user_project_wrapper/user_project_wrapper.v,sha256=zc6GC583muuWtzw3p6v_B1k8j-Oo9WypuQf_8doA4uo,3364
42
42
  librelane/flows/__init__.py,sha256=ghtmUG-taVpHJ3CKJRYZGn3dU0r93araT1EIGlBEsxg,896
43
43
  librelane/flows/builtins.py,sha256=tR14Qc1ZUey2w-Ar4DWOvxuP7LGPtMecCJq8WgcYJpk,773
44
- librelane/flows/classic.py,sha256=MTyAJz5SVJq4S2NAHYbUjLxv0w3wPx1GD5HrkMoTh7w,11082
44
+ librelane/flows/classic.py,sha256=fI-LNhrvi7lzfsHRyJv_yjgFbpbWBVxN-9QpsgDxpTQ,10940
45
45
  librelane/flows/cli.py,sha256=P2LCFn5_RQ88yB0WuetpLAuWeKQXd-DrpCOMgnVh9Mg,16705
46
46
  librelane/flows/flow.py,sha256=wyYw-w6NIbCCfyfgwiq3BpztLlvZkRFUUeePoI9DpaU,34167
47
47
  librelane/flows/misc.py,sha256=32Om3isexesfKKiJZCajNmINc-xdv7eVx_tgoh9SR6U,2015
48
- librelane/flows/optimizing.py,sha256=oBzXOiZqOnLTaGi3YTs1cU72EKKO36dCCK-czkpywKU,6081
48
+ librelane/flows/optimizing.py,sha256=OwZz6WGmXpliwO8vtmhjKHD-kzDyNv-zoCECZIigXsI,6076
49
49
  librelane/flows/sequential.py,sha256=DLzgvHKq0cO-U-eLO98zIFRnhGLfRv80_ozSX973TlI,13350
50
50
  librelane/flows/synth_explore.py,sha256=8mpeuG6oxeEXVQi4NwS4I415eCu7Ak6DN4oK30h1eCQ,7418
51
51
  librelane/logging/__init__.py,sha256=mrTnzjpH6AOu2CiDZYfOMCVByAS2Xeg9HS4FJyXsJOE,1043
@@ -82,18 +82,21 @@ librelane/scripts/odbpy/apply_def_template.py,sha256=Tn6y65biu0bAQ6XilYxq5jn3a_K
82
82
  librelane/scripts/odbpy/cell_frequency.py,sha256=NfGgM8wxIvjM1C_GHUghZPOh8gpdasLOWR4qBdHHLFE,3105
83
83
  librelane/scripts/odbpy/check_antenna_properties.py,sha256=dMD-RcoA7plcAu9IIqa2e-8XCO0EMcKG-6P39D3Gpic,3942
84
84
  librelane/scripts/odbpy/contextualize.py,sha256=G8EEgmK6ISikXD2-Pw-RTs1JxLWPnuppwL7oPfAsb84,4020
85
- librelane/scripts/odbpy/defutil.py,sha256=vOVLEP1WOs2N1JjIoV0mAABWptJAWIzJYIa0JECg8Vc,17987
85
+ librelane/scripts/odbpy/defutil.py,sha256=g0UaAQRt8hXb9nfI6SbMp_Hx__0o1POw33_fS6xyibU,17849
86
86
  librelane/scripts/odbpy/diodes.py,sha256=ZS_1niaTcwvaTTNjJcth4Qepcwxa6aV6E9WM_KiMtTI,11811
87
87
  librelane/scripts/odbpy/disconnected_pins.py,sha256=hS_Iletg7N6K6yN_ccvWxZ3nWNZp4ecUJM-oY0kkEfA,11139
88
- librelane/scripts/odbpy/exception_codes.py,sha256=VXReNio2d9uxU4cXL1PpRxWhhK2_OSs5DeCpVqTDYJE,648
88
+ librelane/scripts/odbpy/eco_buffer.py,sha256=QOL2J0UJQiVvuGFbpdyAj-RRsPfEL-rT_qro3Rp0KeE,6256
89
+ librelane/scripts/odbpy/eco_diode.py,sha256=2LN7fHh9uO9JP3PYIxIwUiP1lyeqdTNF2ADTcY_Bu-g,4281
89
90
  librelane/scripts/odbpy/filter_unannotated.py,sha256=Gvcaj_WNr6TPiHk-36nkMu4betNHZo1g2lD3UcA9hDQ,2950
90
91
  librelane/scripts/odbpy/io_place.py,sha256=LSJIJQDLSOpENyQOg_kVTIbh1AbYLiHIXx0siduo-lg,15589
92
+ librelane/scripts/odbpy/ioplace_parser/__init__.py,sha256=TMKTIWwGJfdSr7dJcsoisUuKlbTKJdHV6-0kB77v2P8,887
93
+ librelane/scripts/odbpy/ioplace_parser/parse.py,sha256=LDncc8r1nDmcTCVtxqBu7xswiesVX6-snYiIKFB_kxs,5594
91
94
  librelane/scripts/odbpy/label_macro_pins.py,sha256=n3o9-_g6HkVP8k49yNnCkQJms9f_ykCE0Rye7bVFtIk,8620
92
95
  librelane/scripts/odbpy/lefutil.py,sha256=XhfWSGHdn96yZWYQAPisgJM0iuY3xw4SW7jmMTzbpZs,3064
93
96
  librelane/scripts/odbpy/placers.py,sha256=mgy_-GYeLDPMG41YAopMTtJyCHP6ucJRk7cJzI9PLRQ,4572
94
97
  librelane/scripts/odbpy/power_utils.py,sha256=al12uMiv8G0yQZOPKXNHYQ1dm2KGlu9xigSuYLEAo_A,14627
95
98
  librelane/scripts/odbpy/random_place.py,sha256=TEsV4LtXQTP8OJvnBh09Siu9fKkwG9UpIkCkQpdXAgU,1649
96
- librelane/scripts/odbpy/reader.py,sha256=uRmcBtD2pN4d9BKfbSjeTyqR2gSoV0SO30VuUSkm-Dk,8449
99
+ librelane/scripts/odbpy/reader.py,sha256=5-hpG3TgmKwJtnbEDQoAPejeDx1QyRBRbIMULMkBesM,8539
97
100
  librelane/scripts/odbpy/remove_buffers.py,sha256=f-kGZIPnMtu4gnl2r2CDkng8U8vUMJKJWNV_akOpc38,5460
98
101
  librelane/scripts/odbpy/snap_to_grid.py,sha256=lULRWlcYXvrTBUpemUPlpO2dBnbFeriuG-DlI4KnViE,1743
99
102
  librelane/scripts/odbpy/wire_lengths.py,sha256=pSPhVnLlvcvmgEh89G8nu8DRaZVP66r-4ieVoV3zrm4,2737
@@ -104,7 +107,7 @@ librelane/scripts/openroad/buffer_list.tcl,sha256=sXygy1KRSUS4dZi1UOpBkGGOuXRVLM
104
107
  librelane/scripts/openroad/common/dpl.tcl,sha256=Nqq5e5OwRoyk8mHfVa5uw3DGKDGMEFrx6odpxanc_Ns,912
105
108
  librelane/scripts/openroad/common/dpl_cell_pad.tcl,sha256=KWVuj8u1-y3ZUiQr48TAsFv1GSzOCVnAjdqfBjtoQxQ,1066
106
109
  librelane/scripts/openroad/common/grt.tcl,sha256=DCKe5D7INCBctitbRdgZNRsBrI9Qo5v7Ag7DF45W4_U,1137
107
- librelane/scripts/openroad/common/io.tcl,sha256=MEePZdAjuBTkWhgFBshrszGo3R-OSNABcrGS62dOq1A,16576
110
+ librelane/scripts/openroad/common/io.tcl,sha256=cPJ4O2nBKrGKON7lO7ZX1j_TpcxQFCw3gH858yTWg8Q,18289
108
111
  librelane/scripts/openroad/common/pdn_cfg.tcl,sha256=KnQAxzlL_261Kp4M02cQ6usZHIRNBj56SAZNn1CqrZc,4552
109
112
  librelane/scripts/openroad/common/resizer.tcl,sha256=3p59NDcXgEkUzg_43dcUYr2KkD__fkADdqCZ3uWsUU4,3478
110
113
  librelane/scripts/openroad/common/set_global_connections.tcl,sha256=zGMz0Hu57ZVdLhz4djJASyre0qOi-dszylo6HD8ClUM,2899
@@ -143,8 +146,8 @@ librelane/state/__init__.py,sha256=rLUdAkeB278r8pB2Jpv-ccmmmP32FR90wANIFHXdA0w,9
143
146
  librelane/state/__main__.py,sha256=Ici4Ejg1ICUZNSYZRguC3BfEk_wFxsmE0ag0Vv8iY1I,1679
144
147
  librelane/state/design_format.py,sha256=9mWBbHrhzludtv3dKB6P4UQncBVTMMtoj69kNgRvh5o,5306
145
148
  librelane/state/state.py,sha256=J05gAeSVDiF76ITuw4WJZ7WkMyG4oTjt_7kpsI3E3PE,11957
146
- librelane/steps/__init__.py,sha256=8jTPCsrzJWjNctKUSXOjxYqqeMQjYkAKslcIXS3GDzg,1647
147
- librelane/steps/__main__.py,sha256=d5tajnx3fscBrDeZsCIySxCiImO0OD6aCCtu4j1qltE,13378
149
+ librelane/steps/__init__.py,sha256=j3JYrdnWM74dYuEvE931oSrQI7FUz-hKWr8Mts8C0wg,1668
150
+ librelane/steps/__main__.py,sha256=GviXtDLISKJCufKxK3oFPOSMF1GyShZbG5RXpVCYFkk,13376
148
151
  librelane/steps/checker.py,sha256=vul1D0cT03144qKK5QAKswClKKICK7kNB4PB6xXykvc,21353
149
152
  librelane/steps/common_variables.py,sha256=qT0VeIstFsDbe8VGAyqXrXxQw69OZ08haM6u1IbdFiE,10429
150
153
  librelane/steps/cvc_rv.py,sha256=32vxFIbzSbrDtE0fXvdoQ-v3LVMrfi3r88f8Y-TKPKg,5531
@@ -152,15 +155,15 @@ librelane/steps/klayout.py,sha256=g7jYz-1cLwgfPTiMJIdAQ9zmkrwNtJLPoRg6PqOUv6Y,16
152
155
  librelane/steps/magic.py,sha256=4o_WarBAQdTTuekP72uovjvqW5wsaDCpMB3LtAhC_IY,20051
153
156
  librelane/steps/misc.py,sha256=Xk_a6JJPljkk8pemu-NtlzDRs-8S7vuRKZKj4pnCRlE,5690
154
157
  librelane/steps/netgen.py,sha256=R9sDWv-9wKMdi2rkuLQdOc4uLlbYhXcKKd6WsZsnLt0,8953
155
- librelane/steps/odb.py,sha256=BNvw_SoXanMpeshzZyRvYW44059xj2o1FWf1OSeFzps,33337
156
- librelane/steps/openroad.py,sha256=pit4e2UmAE6pr3SvheHrrM0JXybA5c6QoYtX9fFaDas,85709
158
+ librelane/steps/odb.py,sha256=_WhAFEVbFioSGsVrGbXQVqcXYAnE22gLA4eF1v028EQ,38030
159
+ librelane/steps/openroad.py,sha256=0uHbFYO3wT9rFkovxMgr4rMzaMpA9DvG8sWLM4L3jn8,85836
157
160
  librelane/steps/openroad_alerts.py,sha256=IJyB4piBDCKXhkJswHGMYCRDwbdQsR0GZlrGGDhmW6Q,3364
158
161
  librelane/steps/pyosys.py,sha256=bBKCIiKxbAQXrEgR1gdg2el-IpuZoUzLOwR62-ilwQg,22326
159
162
  librelane/steps/step.py,sha256=YkUWbxx2dOz0QR90jM5NC7neFkWO1RW5zJc0I_XxRyc,54975
160
163
  librelane/steps/tclstep.py,sha256=0PMWJ6C3dKnlQf9mA9rZntgxUBCiByE9csHcEcM1iq0,10027
161
164
  librelane/steps/verilator.py,sha256=MWx2TpLqYyea9_jSeLG9c2S5ujvYERQZRFNaMhfHxZE,7916
162
165
  librelane/steps/yosys.py,sha256=GX6rTiQG-ZhDxfB9SxrPQ9Sab3WC84p0OUtqiL1Nubk,12533
163
- librelane-2.4.0.dev0.dist-info/METADATA,sha256=WjPPsHVB6NankUUSViUO1KpbjVrpVHyel06ogwlr46w,5841
164
- librelane-2.4.0.dev0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
165
- librelane-2.4.0.dev0.dist-info/entry_points.txt,sha256=GTBvXykNMMFsNKiJFgtEw7P1wb_VZIqVM35EFSpyZQE,263
166
- librelane-2.4.0.dev0.dist-info/RECORD,,
166
+ librelane-2.4.0.dev3.dist-info/METADATA,sha256=ycb_5xJHsFD3ETcy_FObKWoWc64Ck0BpJ4cGB2Ts3DE,6600
167
+ librelane-2.4.0.dev3.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
168
+ librelane-2.4.0.dev3.dist-info/entry_points.txt,sha256=GTBvXykNMMFsNKiJFgtEw7P1wb_VZIqVM35EFSpyZQE,263
169
+ librelane-2.4.0.dev3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.2
2
+ Generator: poetry-core 1.9.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any