librelane 3.0.0.dev26__tar.gz → 3.0.0.dev28__tar.gz

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 (172) hide show
  1. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/PKG-INFO +1 -1
  2. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/__init__.py +1 -1
  3. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/metrics/__main__.py +2 -1
  4. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/misc.py +18 -6
  5. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/tcl.py +42 -0
  6. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/flow.py +12 -0
  7. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/cli.py +2 -2
  8. librelane-3.0.0.dev28/librelane/pdk_hashes.yaml +3 -0
  9. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/klayout/stream_out.py +26 -2
  10. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/extract_spice.tcl +1 -1
  11. librelane-3.0.0.dev28/librelane/scripts/openroad/write_cdl.tcl +23 -0
  12. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/pyosys/json_header.py +1 -1
  13. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/pyosys/synthesize.py +1 -1
  14. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/state/design_format.py +7 -0
  15. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/cvc_rv.py +1 -8
  16. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/klayout.py +207 -2
  17. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/openroad.py +14 -0
  18. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/yosys.py +1 -1
  19. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/pyproject.toml +1 -1
  20. librelane-3.0.0.dev26/librelane/open_pdks_rev +0 -1
  21. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/Readme.md +0 -0
  22. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/__init__.py +0 -0
  23. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/__main__.py +0 -0
  24. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/__version__.py +0 -0
  25. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/cli.py +0 -0
  26. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/drc.py +0 -0
  27. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/generic_dict.py +0 -0
  28. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/metrics/__init__.py +0 -0
  29. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/metrics/library.py +0 -0
  30. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/metrics/metric.py +0 -0
  31. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/metrics/util.py +0 -0
  32. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/ring_buffer.py +0 -0
  33. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/toolbox.py +0 -0
  34. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/tpe.py +0 -0
  35. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/common/types.py +0 -0
  36. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/__init__.py +0 -0
  37. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/__main__.py +0 -0
  38. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/config.py +0 -0
  39. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/pdk_compat.py +0 -0
  40. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/preprocessor.py +0 -0
  41. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/removals.py +0 -0
  42. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/config/variable.py +0 -0
  43. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/container.py +0 -0
  44. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/env_info.py +0 -0
  45. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm/config.yaml +0 -0
  46. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm/pin_order.cfg +0 -0
  47. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm/src/impl.sdc +0 -0
  48. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm/src/signoff.sdc +0 -0
  49. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm/src/spm.v +0 -0
  50. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm/verify/spm_tb.v +0 -0
  51. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm-user_project_wrapper/SPM_example.v +0 -0
  52. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm-user_project_wrapper/base_sdc_file.sdc +0 -0
  53. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm-user_project_wrapper/config-tut.json +0 -0
  54. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm-user_project_wrapper/config.json +0 -0
  55. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm-user_project_wrapper/defines.v +0 -0
  56. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm-user_project_wrapper/template.def +0 -0
  57. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/examples/spm-user_project_wrapper/user_project_wrapper.v +0 -0
  58. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/__init__.py +0 -0
  59. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/builtins.py +0 -0
  60. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/classic.py +0 -0
  61. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/flow.py +0 -0
  62. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/misc.py +0 -0
  63. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/optimizing.py +0 -0
  64. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/sequential.py +0 -0
  65. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/flows/synth_explore.py +0 -0
  66. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/logging/__init__.py +0 -0
  67. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/logging/logger.py +0 -0
  68. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/plugins.py +0 -0
  69. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/py.typed +0 -0
  70. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/base.sdc +0 -0
  71. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/klayout/Readme.md +0 -0
  72. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/klayout/open_design.py +0 -0
  73. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/klayout/render.py +0 -0
  74. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/klayout/xml_drc_report_to_json.py +0 -0
  75. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/klayout/xor.drc +0 -0
  76. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/Readme.md +0 -0
  77. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/common/read.tcl +0 -0
  78. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/def/antenna_check.tcl +0 -0
  79. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/def/mag.tcl +0 -0
  80. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/def/mag_gds.tcl +0 -0
  81. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/drc.tcl +0 -0
  82. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/gds/drc_batch.tcl +0 -0
  83. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/gds/erase_box.tcl +0 -0
  84. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/gds/extras_mag.tcl +0 -0
  85. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/gds/mag_with_pointers.tcl +0 -0
  86. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/get_bbox.tcl +0 -0
  87. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/lef/extras_maglef.tcl +0 -0
  88. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/lef/maglef.tcl +0 -0
  89. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/lef.tcl +0 -0
  90. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/open.tcl +0 -0
  91. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/magic/wrapper.tcl +0 -0
  92. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/netgen/setup.tcl +0 -0
  93. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/apply_def_template.py +0 -0
  94. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/cell_frequency.py +0 -0
  95. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/check_antenna_properties.py +0 -0
  96. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/contextualize.py +0 -0
  97. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/defutil.py +0 -0
  98. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/diodes.py +0 -0
  99. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/disconnected_pins.py +0 -0
  100. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/eco_buffer.py +0 -0
  101. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/eco_diode.py +0 -0
  102. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/filter_unannotated.py +0 -0
  103. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/io_place.py +0 -0
  104. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/ioplace_parser/__init__.py +0 -0
  105. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/ioplace_parser/parse.py +0 -0
  106. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/label_macro_pins.py +0 -0
  107. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/lefutil.py +0 -0
  108. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/placers.py +0 -0
  109. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/power_utils.py +0 -0
  110. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/random_place.py +0 -0
  111. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/reader.py +0 -0
  112. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/remove_buffers.py +0 -0
  113. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/snap_to_grid.py +0 -0
  114. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/odbpy/wire_lengths.py +0 -0
  115. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/antenna_check.tcl +0 -0
  116. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/antenna_repair.tcl +0 -0
  117. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/basic_mp.tcl +0 -0
  118. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/buffer_list.tcl +0 -0
  119. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/dpl.tcl +0 -0
  120. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/dpl_cell_pad.tcl +0 -0
  121. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/grt.tcl +0 -0
  122. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/io.tcl +0 -0
  123. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/pdn_cfg.tcl +0 -0
  124. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/resizer.tcl +0 -0
  125. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/set_global_connections.tcl +0 -0
  126. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/set_layer_adjustments.tcl +0 -0
  127. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/set_power_nets.tcl +0 -0
  128. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/set_rc.tcl +0 -0
  129. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/common/set_routing_layers.tcl +0 -0
  130. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/cts.tcl +0 -0
  131. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/cut_rows.tcl +0 -0
  132. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/dpl.tcl +0 -0
  133. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/drt.tcl +0 -0
  134. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/dump_rc.tcl +0 -0
  135. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/fill.tcl +0 -0
  136. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/floorplan.tcl +0 -0
  137. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/gpl.tcl +0 -0
  138. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/grt.tcl +0 -0
  139. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/gui.tcl +0 -0
  140. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/insert_buffer.tcl +0 -0
  141. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/ioplacer.tcl +0 -0
  142. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/irdrop.tcl +0 -0
  143. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/pdn.tcl +0 -0
  144. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/rcx.tcl +0 -0
  145. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/repair_design.tcl +0 -0
  146. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/repair_design_postgrt.tcl +0 -0
  147. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/rsz_timing_postcts.tcl +0 -0
  148. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/rsz_timing_postgrt.tcl +0 -0
  149. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/sta/check_macro_instances.tcl +0 -0
  150. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/sta/corner.tcl +0 -0
  151. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/tapcell.tcl +0 -0
  152. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/ungpl.tcl +0 -0
  153. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/openroad/write_views.tcl +0 -0
  154. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/pyosys/construct_abc_script.py +0 -0
  155. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/pyosys/ys_common.py +0 -0
  156. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/scripts/tclsh/hello.tcl +0 -0
  157. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/state/__init__.py +0 -0
  158. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/state/__main__.py +0 -0
  159. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/state/state.py +0 -0
  160. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/__init__.py +0 -0
  161. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/__main__.py +0 -0
  162. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/checker.py +0 -0
  163. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/common_variables.py +0 -0
  164. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/magic.py +0 -0
  165. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/misc.py +0 -0
  166. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/netgen.py +0 -0
  167. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/odb.py +0 -0
  168. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/openroad_alerts.py +0 -0
  169. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/pyosys.py +0 -0
  170. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/step.py +0 -0
  171. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/tclstep.py +0 -0
  172. {librelane-3.0.0.dev26 → librelane-3.0.0.dev28}/librelane/steps/verilator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: librelane
3
- Version: 3.0.0.dev26
3
+ Version: 3.0.0.dev28
4
4
  Summary: An infrastructure for implementing chip design flows
5
5
  Home-page: https://github.com/librelane/librelane
6
6
  License: Apache-2.0
@@ -32,7 +32,7 @@ from .misc import (
32
32
  idem,
33
33
  get_librelane_root,
34
34
  get_script_dir,
35
- get_opdks_rev,
35
+ get_pdk_hash,
36
36
  slugify,
37
37
  protected,
38
38
  final,
@@ -158,7 +158,8 @@ def _compare_metric_folders(
158
158
  continue
159
159
  basename = basename[: -len(".metrics.json")]
160
160
 
161
- parts = basename.split("-", maxsplit=2)
161
+ # We have to rsplit, since ihp-sg13g2 contains a "-"
162
+ parts = basename.rsplit("-", maxsplit=2)
162
163
  if len(parts) != 3:
163
164
  raise ValueError(
164
165
  f"Invalid filename {basename}: not in the format {{pdk}}-{{scl}}-{{design_name}}"
@@ -1,3 +1,7 @@
1
+ # Copyright 2025 LibreLane Contributors
2
+ #
3
+ # Adapted from OpenLane
4
+ #
1
5
  # Copyright 2023 Efabless Corporation
2
6
  #
3
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +20,7 @@ import os
16
20
  import re
17
21
  import glob
18
22
  import gzip
23
+ import yaml
19
24
  import typing
20
25
  import pathlib
21
26
  import fnmatch
@@ -37,6 +42,7 @@ import httpx
37
42
 
38
43
  from ..__version__ import __version__
39
44
  from .types import AnyPath, Path
45
+ from ..logging import err
40
46
 
41
47
  T = TypeVar("T")
42
48
 
@@ -68,15 +74,21 @@ def get_script_dir() -> str:
68
74
  )
69
75
 
70
76
 
71
- def get_opdks_rev() -> str:
77
+ def get_pdk_hash(pdk_variant) -> str:
72
78
  """
73
- Gets the Open_PDKs revision confirmed compatible with this version of LibreLane.
79
+ Gets the PDK version hash confirmed compatible with this version of LibreLane.
74
80
  """
75
- return (
76
- open(os.path.join(get_librelane_root(), "open_pdks_rev"), encoding="utf8")
77
- .read()
78
- .strip()
81
+
82
+ with open(os.path.join(get_librelane_root(), "pdk_hashes.yaml"), "r") as file:
83
+ pdk_hashes = yaml.safe_load(file)
84
+ for pdk_family in pdk_hashes:
85
+ if pdk_family in pdk_variant:
86
+ return pdk_hashes[pdk_family]
87
+
88
+ err(
89
+ f"Could not find a PDK family for '{pdk_variant}'. Please specify a PDK manually with '--manual-pdk'."
79
90
  )
91
+ exit(1)
80
92
 
81
93
 
82
94
  # The following code snippet has been adapted under the following license:
@@ -1,3 +1,7 @@
1
+ # Copyright 2025 LibreLane Contributors
2
+ #
3
+ # Adapted from OpenLane
4
+ #
1
5
  # Copyright 2023 Efabless Corporation
2
6
  #
3
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -68,12 +72,50 @@ class TclUtils(object):
68
72
  if value is not None:
69
73
  env_out[match.group(1)] = value
70
74
 
75
+ def py_dict(command, target=None, *args):
76
+ if command == "set":
77
+ if match := _env_rx.fullmatch(target):
78
+
79
+ if len(args) > 1:
80
+ value = args[-1]
81
+ keys = args[:-1]
82
+
83
+ # Create new dict if it does not exist
84
+ if not match.group(1) in env_out:
85
+ env_out[match.group(1)] = {}
86
+
87
+ # set ::env(...) [dict create]
88
+ # will create an empty string ""
89
+ # convert into an empty dictionary
90
+ if env_out[match.group(1)] == "":
91
+ env_out[match.group(1)] = {}
92
+
93
+ # Set key value pair
94
+ cur_dict = env_out[match.group(1)]
95
+
96
+ # Create all nested dicts
97
+ for key in keys[:-1]:
98
+ if key in cur_dict:
99
+ cur_dict = cur_dict[key]
100
+ else:
101
+ cur_dict[key] = {}
102
+ cur_dict = cur_dict[key]
103
+
104
+ # Finally set the value
105
+ cur_dict[keys[-1]] = value
106
+
71
107
  py_set_name = interpreter.register(py_set)
108
+ py_dict_name = interpreter.register(py_dict)
72
109
  interpreter.call("rename", py_set_name, "_py_set")
73
110
  interpreter.call("rename", "set", "_orig_set")
111
+ interpreter.call("rename", py_dict_name, "_py_dict")
112
+ interpreter.call("rename", "dict", "_orig_dict")
74
113
  interpreter.eval(
75
114
  "proc set args { _py_set {*}$args; tailcall _orig_set {*}$args; }"
76
115
  )
116
+ interpreter.eval(
117
+ "proc dict args { _py_dict {*}$args; tailcall _orig_dict {*}$args; }"
118
+ )
77
119
 
78
120
  interpreter.eval(tcl_in)
79
121
 
@@ -195,6 +195,13 @@ scl_variables = [
195
195
  "Path(s) to cells' SPICE model(s)",
196
196
  pdk=True,
197
197
  ),
198
+ Variable(
199
+ "CELL_CDLS",
200
+ Optional[List[Path]],
201
+ description="A circuit-design language view of the standard cell library.",
202
+ pdk=True,
203
+ deprecated_names=["STD_CELL_LIBRARY_CDL"],
204
+ ),
198
205
  Variable(
199
206
  "SYNTH_EXCLUDED_CELL_FILE",
200
207
  Path,
@@ -424,6 +431,11 @@ option_variables = [
424
431
  Optional[List[Path]],
425
432
  "Specifies miscellaneous SPICE models to be loaded indiscriminately whenever SPICE models are loaded.",
426
433
  ),
434
+ Variable(
435
+ "EXTRA_CDLS",
436
+ Optional[List[Path]],
437
+ "Specifies miscellaneous CDL netlists to be loaded indiscriminately whenever CDL netlists are loaded.",
438
+ ),
427
439
  Variable(
428
440
  "EXTRA_LIBS",
429
441
  Optional[List[Path]],
@@ -34,7 +34,7 @@ from cloup.constraints import (
34
34
  from cloup.typing import Decorator
35
35
 
36
36
  from .flow import Flow
37
- from ..common import set_tpe, cli, get_opdks_rev, _get_process_limit
37
+ from ..common import set_tpe, cli, get_pdk_hash, _get_process_limit
38
38
  from ..logging import set_log_level, verbose, err, options, LogLevels
39
39
  from ..state import State, InvalidState
40
40
 
@@ -421,7 +421,7 @@ def cloup_flow_opts(
421
421
  import ciel
422
422
  from ciel.source import StaticWebDataSource
423
423
 
424
- opdks_rev = volare_pdk_override or get_opdks_rev()
424
+ opdks_rev = volare_pdk_override or get_pdk_hash(pdk)
425
425
  ciel_home = ciel.get_ciel_home(pdk_root)
426
426
 
427
427
  include_libraries = ["default"]
@@ -0,0 +1,3 @@
1
+ sky130: 8afc8346a57fe1ab7934ba5a6056ea8b43078e71
2
+ gf180mcu: 8afc8346a57fe1ab7934ba5a6056ea8b43078e71
3
+ ihp-sg13g2: cb7daaa8901016cf7c5d272dfa322c41f024931f
@@ -90,6 +90,13 @@ import click
90
90
  "input",
91
91
  type=click.Path(exists=True, file_okay=True, dir_okay=False),
92
92
  )
93
+ @click.option(
94
+ "--conflict-resolution",
95
+ "conflict_resolution",
96
+ type=str,
97
+ default="RenameCell",
98
+ help="Cell conflict resolution handling.",
99
+ )
93
100
  def stream_out(
94
101
  output: str,
95
102
  input_lefs: Tuple[str, ...],
@@ -100,6 +107,7 @@ def stream_out(
100
107
  seal_gds: Optional[str],
101
108
  design_name: str,
102
109
  input: str,
110
+ conflict_resolution: str,
103
111
  ): # Load technology file
104
112
  try:
105
113
  tech = pya.Technology()
@@ -109,6 +117,22 @@ def stream_out(
109
117
  layout_options.lefdef_config.lef_files = list(input_lefs)
110
118
  layout_options.lefdef_config.map_file = lym
111
119
 
120
+ cell_conflict_resolution = {
121
+ "AddToCell": pya.LoadLayoutOptions.CellConflictResolution.AddToCell,
122
+ "OverwriteCell": pya.LoadLayoutOptions.CellConflictResolution.OverwriteCell,
123
+ "RenameCell": pya.LoadLayoutOptions.CellConflictResolution.RenameCell,
124
+ "SkipNewCell": pya.LoadLayoutOptions.CellConflictResolution.SkipNewCell,
125
+ }.get(conflict_resolution)
126
+
127
+ if cell_conflict_resolution is None:
128
+ print(
129
+ f"[ERROR] Unknown conflict resolution: '{conflict_resolution}'.",
130
+ file=sys.stderr,
131
+ )
132
+ exit(1)
133
+ else:
134
+ layout_options.cell_conflict_resolution = cell_conflict_resolution
135
+
112
136
  # Load def file
113
137
  main_layout = pya.Layout()
114
138
  # main_layout.load_layer_props(props_file)
@@ -126,7 +150,7 @@ def stream_out(
126
150
  # Load in the gds to merge
127
151
  print("[INFO] Merging GDS files…")
128
152
  for gds in input_gds_files:
129
- main_layout.read(gds)
153
+ main_layout.read(gds, layout_options)
130
154
 
131
155
  # Copy the top level only to a new layout
132
156
  print(f"[INFO] Copying top level cell '{design_name}'…")
@@ -138,7 +162,7 @@ def stream_out(
138
162
  print("[INFO] Checking for missing GDS…")
139
163
  missing_gds = False
140
164
  for i in top_only_layout.each_cell():
141
- if i.is_empty():
165
+ if i.is_ghost_cell():
142
166
  missing_gds = True
143
167
  print(
144
168
  f"[ERROR] LEF Cell '{i.name}' has no matching GDS cell.",
@@ -12,7 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  set f [open $::env(STEP_DIR)/cif_scale.txt "w"]
15
- puts $f "[magic::i2u 1]"
15
+ puts $f [expr {((round([magic::cif scale output] * 10000)) / 10000.0) * 1}]
16
16
  close $f
17
17
 
18
18
  if { $::env(MAGIC_EXT_USE_GDS) } {
@@ -0,0 +1,23 @@
1
+ #
2
+ # Write CDL netlist of the current design
3
+ #
4
+
5
+ # Load design database
6
+ source $::env(SCRIPTS_DIR)/openroad/common/io.tcl
7
+ read_current_odb
8
+
9
+ # Collect masters CDL
10
+ set masters {}
11
+
12
+ foreach cdl $::env(CELL_CDLS) {
13
+ lappend masters $cdl
14
+ }
15
+
16
+ if { [info exist ::env(EXTRA_CDLS)] } {
17
+ foreach cdl $::env(EXTRA_CDLS) {
18
+ lappend masters $cdl
19
+ }
20
+ }
21
+
22
+ # Write only the CDL
23
+ write_cdl -include_fillers -masters "$masters" $::env(STEP_DIR)/$::env(DESIGN_NAME).cdl
@@ -38,7 +38,7 @@ def json_header(
38
38
  defines = (
39
39
  (config["VERILOG_DEFINES"] or [])
40
40
  + [
41
- f"PDK_{config['PDK']}",
41
+ f"PDK_{config['PDK'].replace('-','_')}",
42
42
  f"SCL_{config['STD_CELL_LIBRARY']}",
43
43
  "__librelane__",
44
44
  "__pnr__",
@@ -227,7 +227,7 @@ def synthesize(
227
227
 
228
228
  includes = config.get("VERILOG_INCLUDE_DIRS") or []
229
229
  defines = (config.get("VERILOG_DEFINES") or []) + [
230
- f"PDK_{config['PDK']}",
230
+ f"PDK_{config['PDK'].replace('-','_')}",
231
231
  f"SCL_{config['STD_CELL_LIBRARY']}",
232
232
  "__librelane__",
233
233
  "__pnr__",
@@ -239,6 +239,13 @@ DesignFormat(
239
239
  alts=["SPICE"],
240
240
  ).register()
241
241
 
242
+ DesignFormat(
243
+ "cdl",
244
+ "cdl",
245
+ "Circuit Design Language",
246
+ alts=["CDL"],
247
+ ).register()
248
+
242
249
  DesignFormat(
243
250
  "gds",
244
251
  "gds",
@@ -16,7 +16,7 @@ import re
16
16
  import json
17
17
  from enum import Enum
18
18
  from io import StringIO, TextIOWrapper
19
- from typing import List, Optional, Tuple
19
+ from typing import Optional, Tuple
20
20
 
21
21
  from .step import StepException, ViewsUpdate, MetricsUpdate, Step
22
22
  from ..common import Path
@@ -124,13 +124,6 @@ class ERC(Step):
124
124
  description="",
125
125
  pdk=True,
126
126
  ),
127
- Variable(
128
- "CELL_CDLS",
129
- List[Path],
130
- description="A circuit-design language view of the standard cell library.",
131
- pdk=True,
132
- deprecated_names=["STD_CELL_LIBRARY_CDL"],
133
- ),
134
127
  ]
135
128
 
136
129
  def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
@@ -1,3 +1,7 @@
1
+ # Copyright 2025 LibreLane Contributors
2
+ #
3
+ # Adapted from OpenLane
4
+ #
1
5
  # Copyright 2023 Efabless Corporation
2
6
  #
3
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +23,8 @@ import shutil
19
23
  import subprocess
20
24
  from os.path import abspath
21
25
  from base64 import b64encode
22
- from typing import Any, Dict, Optional, List, Sequence, Tuple, Union
26
+ from tempfile import NamedTemporaryFile
27
+ from typing import Any, Dict, Optional, List, Literal, Sequence, Tuple, Union
23
28
 
24
29
  from .step import ViewsUpdate, MetricsUpdate, Step, StepError, StepException
25
30
 
@@ -196,6 +201,17 @@ class StreamOut(KLayoutStep):
196
201
  inputs = [DesignFormat.DEF]
197
202
  outputs = [DesignFormat.GDS, DesignFormat.KLAYOUT_GDS]
198
203
 
204
+ config_vars = KLayoutStep.config_vars + [
205
+ Variable(
206
+ "KLAYOUT_CONFLICT_RESOLUTION",
207
+ Optional[
208
+ Literal["AddToCell", "OverwriteCell", "RenameCell", "SkipNewCell"]
209
+ ],
210
+ "Specifies the conflict resolution if a cell name conflict arises.",
211
+ default="RenameCell",
212
+ ),
213
+ ]
214
+
199
215
  def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
200
216
  views_updates: ViewsUpdate = {}
201
217
 
@@ -218,6 +234,8 @@ class StreamOut(KLayoutStep):
218
234
  abspath(klayout_gds_out),
219
235
  "--top",
220
236
  self.config["DESIGN_NAME"],
237
+ "--conflict-resolution",
238
+ self.config["KLAYOUT_CONFLICT_RESOLUTION"],
221
239
  ]
222
240
  + self.get_cli_args(include_lefs=True, include_gds=True),
223
241
  env=env,
@@ -431,10 +449,77 @@ class DRC(KLayoutStep):
431
449
  )
432
450
  return subprocess_result["generated_metrics"]
433
451
 
452
+ def run_ihp_sg13g2(self, state_in: State, **kwargs) -> MetricsUpdate:
453
+ kwargs, env = self.extract_env(kwargs)
454
+
455
+ drc_script_path = self.config["KLAYOUT_DRC_RUNSET"]
456
+
457
+ reports_dir = os.path.join(self.step_dir, "reports")
458
+ mkdirp(reports_dir)
459
+ xml_report = os.path.join(reports_dir, "drc_violations.klayout.xml")
460
+ json_report = os.path.join(reports_dir, "drc_violations.klayout.json")
461
+
462
+ input_view = state_in[DesignFormat.GDS]
463
+ assert isinstance(input_view, Path)
464
+
465
+ opts = []
466
+ for k, v in self.config["KLAYOUT_DRC_OPTIONS"].items():
467
+ opts.extend(
468
+ [
469
+ "-rd",
470
+ f"{k}={v}",
471
+ ]
472
+ )
473
+
474
+ threads = self.config["KLAYOUT_DRC_THREADS"] or str(_get_process_limit())
475
+ if threads != "1":
476
+ opts.extend(
477
+ [
478
+ "-rd",
479
+ f"threads={threads}",
480
+ ]
481
+ )
482
+
483
+ info(f"Running KLayout DRC with {threads} threads…")
484
+
485
+ # Not pya script - DRC script is not part of OpenLane
486
+ self.run_subprocess(
487
+ [
488
+ "klayout",
489
+ "-b",
490
+ "-zz",
491
+ "-r",
492
+ drc_script_path,
493
+ "-rd",
494
+ f"in_gds={abspath(input_view)}",
495
+ "-rd",
496
+ f"report_file={abspath(xml_report)}",
497
+ *opts,
498
+ ]
499
+ )
500
+
501
+ subprocess_result = self.run_pya_script(
502
+ [
503
+ "python3",
504
+ os.path.join(
505
+ get_script_dir(),
506
+ "klayout",
507
+ "xml_drc_report_to_json.py",
508
+ ),
509
+ f"--xml-file={abspath(xml_report)}",
510
+ f"--json-file={abspath(json_report)}",
511
+ ],
512
+ env=env,
513
+ log_to=os.path.join(self.step_dir, "xml_drc_report_to_json.log"),
514
+ )
515
+ return subprocess_result["generated_metrics"]
516
+
434
517
  def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
435
518
  metrics_updates: MetricsUpdate = {}
436
519
  if self.config["PDK"] in ["sky130A", "sky130B"]:
437
520
  metrics_updates = self.run_sky130(state_in, **kwargs)
521
+ elif self.config["PDK"] in ["ihp-sg13g2"]:
522
+ metrics_updates = self.run_ihp_sg13g2(state_in, **kwargs)
438
523
  else:
439
524
  self.warn(
440
525
  f"KLayout DRC is not supported for the {self.config['PDK']} PDK. This step will be skipped."
@@ -443,6 +528,126 @@ class DRC(KLayoutStep):
443
528
  return {}, metrics_updates
444
529
 
445
530
 
531
+ @Step.factory.register()
532
+ class LVS(KLayoutStep):
533
+ id = "KLayout.LVS"
534
+ name = "Layout Versus Schematic (KLayout)"
535
+
536
+ inputs = [
537
+ DesignFormat.CDL,
538
+ DesignFormat.GDS,
539
+ ]
540
+ outputs = [DesignFormat.SPICE]
541
+
542
+ config_vars = KLayoutStep.config_vars + [
543
+ Variable(
544
+ "KLAYOUT_LVS_SCRIPT",
545
+ Optional[Path],
546
+ "A path to KLayout LVS script.",
547
+ pdk=True,
548
+ ),
549
+ Variable(
550
+ "KLAYOUT_LVS_OPTIONS",
551
+ Optional[Dict[str, Union[bool, int, str]]],
552
+ "Options passed directly to the KLayout LVS script. They vary from one PDK to another.",
553
+ pdk=True,
554
+ ),
555
+ ]
556
+
557
+ def run_ihp_sg13g2(
558
+ self, state_in: State, **kwargs
559
+ ) -> Tuple[ViewsUpdate, MetricsUpdate]:
560
+ kwargs, env = self.extract_env(kwargs)
561
+
562
+ lvs_script_path = self.config["KLAYOUT_LVS_SCRIPT"]
563
+
564
+ reports_dir = os.path.join(self.step_dir, "reports")
565
+ mkdirp(reports_dir)
566
+ lvsdb_report = os.path.join(reports_dir, "lvs.klayout.lvsdb")
567
+
568
+ input_view_gds = state_in[DesignFormat.GDS]
569
+ input_view_cdl = state_in[DesignFormat.CDL]
570
+ assert isinstance(input_view_gds, Path)
571
+ assert isinstance(input_view_cdl, Path)
572
+
573
+ output_spice = os.path.join(
574
+ self.step_dir,
575
+ f"{self.config['DESIGN_NAME']}.{DesignFormat.SPICE.value.extension}",
576
+ )
577
+
578
+ with NamedTemporaryFile("w") as f:
579
+ # Merge all CDL inputs
580
+ cdl_lst = [input_view_cdl]
581
+ cdl_lst.extend(self.config["CELL_CDLS"] or [])
582
+ cdl_lst.extend(self.config["EXTRA_CDLS"] or [])
583
+
584
+ for fn in cdl_lst:
585
+ with open(fn, "r") as cdl_fh:
586
+ f.write(cdl_fh.read())
587
+
588
+ opts = []
589
+ for k, v in self.config["KLAYOUT_LVS_OPTIONS"].items():
590
+ opts.extend(
591
+ [
592
+ "-rd",
593
+ f"{k}={v}",
594
+ ]
595
+ )
596
+
597
+ # Not pya script - LVS script is not part of LibreLane
598
+ subprocess_result = self.run_subprocess(
599
+ [
600
+ "klayout",
601
+ "-b",
602
+ "-zz",
603
+ "-r",
604
+ lvs_script_path,
605
+ "-rd",
606
+ f"input={abspath(input_view_gds)}",
607
+ "-rd",
608
+ f"schematic={abspath(f.name)}",
609
+ "-rd",
610
+ f"report={abspath(lvsdb_report)}",
611
+ "-rd",
612
+ f"target_netlist={abspath(output_spice)}",
613
+ ]
614
+ + opts,
615
+ env=env,
616
+ )
617
+
618
+ with open(subprocess_result["log_path"]) as fh:
619
+ for line in fh:
620
+ if "INFO : Congratulations! Netlists match" in line:
621
+ ok = True
622
+ break
623
+ elif "ERROR : Netlists don't match" in line:
624
+ ok = False
625
+ break
626
+ else:
627
+ ok = False
628
+
629
+ views_updates: ViewsUpdate = {
630
+ DesignFormat.SPICE: Path(output_spice),
631
+ }
632
+ metrics_updates: MetricsUpdate = {
633
+ "design__lvs_error__count": 0 if ok else 1,
634
+ }
635
+
636
+ return views_updates, metrics_updates
637
+
638
+ def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
639
+ metrics_updates: MetricsUpdate = {}
640
+ views_updates: ViewsUpdate = {}
641
+ if self.config["PDK"] in ["ihp-sg13g2"]:
642
+ views_updates, metrics_updates = self.run_ihp_sg13g2(state_in, **kwargs)
643
+ else:
644
+ self.warn(
645
+ f"KLayout LVS is not supported for the {self.config['PDK']} PDK. This step will be skipped."
646
+ )
647
+
648
+ return views_updates, metrics_updates
649
+
650
+
446
651
  @Step.factory.register()
447
652
  class OpenGUI(KLayoutStep):
448
653
  """
@@ -480,7 +685,7 @@ class OpenGUI(KLayoutStep):
480
685
 
481
686
  layout = state_in[DesignFormat.DEF]
482
687
  if self.config["KLAYOUT_GUI_USE_GDS"]:
483
- if gds := state_in[DesignFormat.GDS]:
688
+ if gds := state_in.get(DesignFormat.GDS):
484
689
  layout = gds
485
690
  assert isinstance(layout, Path)
486
691
 
@@ -2188,6 +2188,20 @@ class WriteViews(OpenROADStep):
2188
2188
  return os.path.join(get_script_dir(), "openroad", "write_views.tcl")
2189
2189
 
2190
2190
 
2191
+ @Step.factory.register()
2192
+ class WriteCDL(OpenROADStep):
2193
+ """
2194
+ Write CDL view of an ODB design
2195
+ """
2196
+
2197
+ id = "OpenROAD.WriteCDL"
2198
+ name = "Write CDL"
2199
+ outputs = [DesignFormat.CDL]
2200
+
2201
+ def get_script_path(self):
2202
+ return os.path.join(get_script_dir(), "openroad", "write_cdl.tcl")
2203
+
2204
+
2191
2205
  # Resizer Steps
2192
2206
 
2193
2207
 
@@ -48,7 +48,7 @@ def _generate_read_deps(
48
48
  commands = ""
49
49
 
50
50
  synth_defines = [
51
- f"PDK_{config['PDK']}",
51
+ f"PDK_{config['PDK'].replace('-','_')}",
52
52
  f"SCL_{config['STD_CELL_LIBRARY']}",
53
53
  "__librelane__",
54
54
  "__pnr__",
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "librelane"
3
- version = "3.0.0.dev26"
3
+ version = "3.0.0.dev28"
4
4
  description = "An infrastructure for implementing chip design flows"
5
5
  # Technically, maintainer. We cannot use the maintainers field until
6
6
  # poetry-core>=2.0.0 which requires Python version 3.9+. This field does
@@ -1 +0,0 @@
1
- 0fe599b2afb6708d281543108caf8310912f54af