librelane 3.0.4__tar.gz → 3.1.0.dev2__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.
Files changed (178) hide show
  1. {librelane-3.0.4 → librelane-3.1.0.dev2}/PKG-INFO +1 -1
  2. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/toolbox.py +7 -1
  3. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/config.py +4 -4
  4. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/flow.py +40 -11
  5. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/pdk_compat.py +3 -3
  6. librelane-3.1.0.dev2/librelane/pdk_hashes.yaml +3 -0
  7. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/common/read.tcl +24 -45
  8. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/drc.tcl +4 -0
  9. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/power_utils.py +9 -2
  10. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/io.tcl +0 -14
  11. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/pad_cfg.tcl +30 -13
  12. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/pdn_cfg.tcl +1 -0
  13. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/repair_design.tcl +5 -2
  14. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/pyosys/json_header.py +5 -0
  15. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/pyosys/synthesize.py +15 -6
  16. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/common_variables.py +6 -0
  17. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/klayout.py +12 -9
  18. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/odb.py +2 -1
  19. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/openroad.py +17 -2
  20. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/pyosys.py +8 -3
  21. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/verilator.py +5 -1
  22. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/yosys.py +5 -4
  23. {librelane-3.0.4 → librelane-3.1.0.dev2}/pyproject.toml +1 -1
  24. librelane-3.0.4/librelane/pdk_hashes.yaml +0 -3
  25. {librelane-3.0.4 → librelane-3.1.0.dev2}/Readme.md +0 -0
  26. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/__init__.py +0 -0
  27. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/__main__.py +0 -0
  28. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/__version__.py +0 -0
  29. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/__init__.py +0 -0
  30. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/cli.py +0 -0
  31. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/drc.py +0 -0
  32. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/generic_dict.py +0 -0
  33. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/metrics/__init__.py +0 -0
  34. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/metrics/__main__.py +0 -0
  35. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/metrics/library.py +0 -0
  36. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/metrics/metric.py +0 -0
  37. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/metrics/util.py +0 -0
  38. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/misc.py +0 -0
  39. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/ring_buffer.py +0 -0
  40. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/tcl.py +0 -0
  41. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/tpe.py +0 -0
  42. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/common/types.py +0 -0
  43. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/__init__.py +0 -0
  44. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/__main__.py +0 -0
  45. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/preprocessor.py +0 -0
  46. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/removals.py +0 -0
  47. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/config/variable.py +0 -0
  48. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/container.py +0 -0
  49. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/env_info.py +0 -0
  50. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/hold_eco_demo/config.yaml +0 -0
  51. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/hold_eco_demo/demo.v +0 -0
  52. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm/config.yaml +0 -0
  53. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm/pin_order.cfg +0 -0
  54. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm/src/impl.sdc +0 -0
  55. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm/src/signoff.sdc +0 -0
  56. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm/src/spm.v +0 -0
  57. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm/verify/spm_tb.v +0 -0
  58. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm-user_project_wrapper/SPM_example.v +0 -0
  59. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm-user_project_wrapper/base_sdc_file.sdc +0 -0
  60. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm-user_project_wrapper/config-tut.json +0 -0
  61. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm-user_project_wrapper/config.json +0 -0
  62. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm-user_project_wrapper/defines.v +0 -0
  63. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm-user_project_wrapper/template.def +0 -0
  64. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/examples/spm-user_project_wrapper/user_project_wrapper.v +0 -0
  65. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/__init__.py +0 -0
  66. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/builtins.py +0 -0
  67. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/chip.py +0 -0
  68. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/classic.py +0 -0
  69. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/cli.py +0 -0
  70. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/flow.py +0 -0
  71. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/misc.py +0 -0
  72. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/optimizing.py +0 -0
  73. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/sequential.py +0 -0
  74. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/flows/synth_explore.py +0 -0
  75. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/help/__main__.py +0 -0
  76. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/logging/__init__.py +0 -0
  77. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/logging/logger.py +0 -0
  78. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/plugins.py +0 -0
  79. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/py.typed +0 -0
  80. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/base.sdc +0 -0
  81. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/klayout/Readme.md +0 -0
  82. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/klayout/insert_cell.py +0 -0
  83. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/klayout/open_design.py +0 -0
  84. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/klayout/render.py +0 -0
  85. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/klayout/stream_out.py +0 -0
  86. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/klayout/xml_drc_report_to_json.py +0 -0
  87. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/klayout/xor.drc +0 -0
  88. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/Readme.md +0 -0
  89. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/def/antenna_check.tcl +0 -0
  90. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/def/mag.tcl +0 -0
  91. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/def/mag_gds.tcl +0 -0
  92. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/extract_spice.tcl +0 -0
  93. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/gds/drc_batch.tcl +0 -0
  94. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/gds/erase_box.tcl +0 -0
  95. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/gds/extras_mag.tcl +0 -0
  96. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/gds/mag_with_pointers.tcl +0 -0
  97. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/get_bbox.tcl +0 -0
  98. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/lef/extras_maglef.tcl +0 -0
  99. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/lef/maglef.tcl +0 -0
  100. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/lef.tcl +0 -0
  101. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/open.tcl +0 -0
  102. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/spice_rcx.tcl +0 -0
  103. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/magic/wrapper.tcl +0 -0
  104. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/netgen/setup.tcl +0 -0
  105. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/apply_def_template.py +0 -0
  106. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/cell_frequency.py +0 -0
  107. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/check_antenna_properties.py +0 -0
  108. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/contextualize.py +0 -0
  109. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/defutil.py +0 -0
  110. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/diodes.py +0 -0
  111. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/disconnected_pins.py +0 -0
  112. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/eco_buffer.py +0 -0
  113. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/eco_diode.py +0 -0
  114. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/filter_unannotated.py +0 -0
  115. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/io_place.py +0 -0
  116. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/ioplace_parser/__init__.py +0 -0
  117. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/ioplace_parser/parse.py +0 -0
  118. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/label_macro_pins.py +0 -0
  119. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/lefutil.py +0 -0
  120. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/placers.py +0 -0
  121. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/random_place.py +0 -0
  122. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/reader.py +0 -0
  123. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/remove_buffers.py +0 -0
  124. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/snap_to_grid.py +0 -0
  125. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/odbpy/wire_lengths.py +0 -0
  126. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/antenna_check.tcl +0 -0
  127. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/antenna_repair.tcl +0 -0
  128. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/buffer_list.tcl +0 -0
  129. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/dpl.tcl +0 -0
  130. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/dpl_cell_pad.tcl +0 -0
  131. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/grt.tcl +0 -0
  132. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/resizer.tcl +0 -0
  133. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/set_global_connections.tcl +0 -0
  134. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/set_layer_adjustments.tcl +0 -0
  135. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/set_power_nets.tcl +0 -0
  136. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/set_rc.tcl +0 -0
  137. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/common/set_routing_layers.tcl +0 -0
  138. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/cts.tcl +0 -0
  139. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/cut_rows.tcl +0 -0
  140. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/dpl.tcl +0 -0
  141. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/drt.tcl +0 -0
  142. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/dump_rc.tcl +0 -0
  143. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/fill.tcl +0 -0
  144. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/floorplan.tcl +0 -0
  145. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/gpl.tcl +0 -0
  146. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/grt.tcl +0 -0
  147. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/gui.tcl +0 -0
  148. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/insert_buffer.tcl +0 -0
  149. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/ioplacer.tcl +0 -0
  150. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/irdrop.tcl +0 -0
  151. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/pad.tcl +0 -0
  152. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/pdn.tcl +0 -0
  153. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/rcx.tcl +0 -0
  154. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/repair_design_postgrt.tcl +0 -0
  155. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/rsz_timing_postcts.tcl +0 -0
  156. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/rsz_timing_postgrt.tcl +0 -0
  157. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/sta/check_macro_instances.tcl +0 -0
  158. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/sta/corner.tcl +0 -0
  159. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/tapcell.tcl +0 -0
  160. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/ungpl.tcl +0 -0
  161. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/write_cdl.tcl +0 -0
  162. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/openroad/write_views.tcl +0 -0
  163. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/pyosys/construct_abc_script.py +0 -0
  164. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/pyosys/ys_common.py +0 -0
  165. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/scripts/tclsh/hello.tcl +0 -0
  166. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/state/__init__.py +0 -0
  167. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/state/__main__.py +0 -0
  168. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/state/design_format.py +0 -0
  169. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/state/state.py +0 -0
  170. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/__init__.py +0 -0
  171. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/__main__.py +0 -0
  172. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/checker.py +0 -0
  173. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/magic.py +0 -0
  174. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/misc.py +0 -0
  175. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/netgen.py +0 -0
  176. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/openroad_alerts.py +0 -0
  177. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/step.py +0 -0
  178. {librelane-3.0.4 → librelane-3.1.0.dev2}/librelane/steps/tclstep.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: librelane
3
- Version: 3.0.4
3
+ Version: 3.1.0.dev2
4
4
  Summary: An infrastructure for implementing chip design flows
5
5
  License-Expression: Apache-2.0
6
6
  Maintainer: Mohamed Gaber
@@ -232,10 +232,16 @@ class Toolbox(object):
232
232
 
233
233
  timing_corner = timing_corner or config["DEFAULT_CORNER"]
234
234
 
235
- all_libs: List[Path] = self.filter_views(config, config["LIB"], timing_corner)
235
+ # Filter the cell libs
236
+ all_libs: List[Path] = self.filter_views(
237
+ config, config["CELL_LIBS"], timing_corner
238
+ )
236
239
  if len(all_libs) == 0:
237
240
  warn(f"No SCL lib files found for {timing_corner}.")
238
241
 
242
+ # Add optional I/O pad libs
243
+ all_libs += self.filter_views(config, config["PAD_LIBS"], timing_corner)
244
+
239
245
  all_netlists: List[Path] = []
240
246
  all_spefs: List[Tuple[str, Path]] = []
241
247
 
@@ -495,10 +495,10 @@ class Config(GenericImmutableDict[str, Any]):
495
495
  :param pdk: A process design kit to use. Required unless specified via the
496
496
  "PDK" key in a configuration object.
497
497
 
498
- :param pdk_root: Required if Volare is not installed.
498
+ :param pdk_root: Required if Ciel is not installed.
499
499
 
500
- If Volare is installed, this value can be used to optionally override
501
- Volare's default.
500
+ If Ciel is installed, this value can be used to optionally override
501
+ Ciel's default.
502
502
 
503
503
  :param scl: A standard cell library to use. If not specified, the PDK's
504
504
  default standard cell library will be used instead.
@@ -713,7 +713,7 @@ class Config(GenericImmutableDict[str, Any]):
713
713
  pdk=pdk,
714
714
  pdkpath=pdkpath,
715
715
  scl=mutable[SpecialKeys.scl],
716
- pad=mutable.get(SpecialKeys.pad, None),
716
+ pad=mutable.get(SpecialKeys.pad, pad),
717
717
  design_dir=design_dir,
718
718
  )
719
719
  )
@@ -18,7 +18,7 @@
18
18
  import os
19
19
 
20
20
  from decimal import Decimal
21
- from typing import List, Optional, Dict, Sequence, Union, Tuple
21
+ from typing import List, Optional, Dict, Sequence, Union, Tuple, Literal
22
22
 
23
23
  from .variable import Variable, Macro
24
24
  from ..common import Path, get_script_dir
@@ -39,6 +39,12 @@ pdk_variables = [
39
39
  "Specifies the default standard cell library to be used under the specified PDK. Must be a valid C identifier, i.e., matches the regular expression `[_a-zA-Z][_a-zA-Z0-9]+`.",
40
40
  pdk=True,
41
41
  ),
42
+ Variable(
43
+ "PAD_CELL_LIBRARY",
44
+ Optional[str],
45
+ "Specifies the default pad cell library to be used under the specified PDK. Must be a valid C identifier, i.e., matches the regular expression `[_a-zA-Z][_a-zA-Z0-9]+`.",
46
+ pdk=True,
47
+ ),
42
48
  Variable(
43
49
  "VDD_PIN",
44
50
  str,
@@ -127,9 +133,10 @@ scl_variables = [
127
133
  deprecated_names=["DECAP_CELL"],
128
134
  ),
129
135
  Variable(
130
- "LIB",
136
+ "CELL_LIBS",
131
137
  Dict[str, List[Path]],
132
138
  "A map from corner patterns to a list of associated liberty files. Exactly one entry must match the `DEFAULT_CORNER`.",
139
+ deprecated_names=["LIB"],
133
140
  pdk=True,
134
141
  ),
135
142
  Variable(
@@ -427,9 +434,10 @@ option_variables = [
427
434
 
428
435
  pad_variables = [
429
436
  Variable(
430
- "PAD_GDS",
431
- Optional[List[Path]],
432
- "Path(s) to IO pad GDS file(s).",
437
+ "PAD_LIBS",
438
+ Optional[Dict[str, List[Path]]],
439
+ "A map from corner patterns to a list of associated liberty files. Exactly one entry must match the `DEFAULT_CORNER`.",
440
+ default={},
433
441
  pdk=True,
434
442
  ),
435
443
  Variable(
@@ -438,6 +446,12 @@ pad_variables = [
438
446
  "Path(s) to IO pad LEF file(s).",
439
447
  pdk=True,
440
448
  ),
449
+ Variable(
450
+ "PAD_GDS",
451
+ Optional[List[Path]],
452
+ "Path(s) to IO pad GDS file(s).",
453
+ pdk=True,
454
+ ),
441
455
  Variable(
442
456
  "PAD_VERILOG_MODELS",
443
457
  Optional[List[Path]],
@@ -456,12 +470,6 @@ pad_variables = [
456
470
  description="A circuit-design language view of the io pad library.",
457
471
  pdk=True,
458
472
  ),
459
- Variable(
460
- "PAD_LIBS",
461
- Optional[Dict[str, List[Path]]],
462
- "A map from corner patterns to a list of associated liberty files. Exactly one entry must match the `DEFAULT_CORNER`.",
463
- pdk=True,
464
- ),
465
473
  Variable(
466
474
  "PAD_CORNER",
467
475
  Optional[List[str]],
@@ -535,6 +543,27 @@ pad_variables = [
535
543
  units="µm",
536
544
  pdk=True,
537
545
  ),
546
+ Variable(
547
+ "PAD_ROTATION_HORIZONTAL",
548
+ Optional[Literal["R0", "MY", "R90", "MXR90", "R180", "MX", "R270", "MYR90"]],
549
+ "Rotation to apply to the horizontal sites to ensure pads are placed correctly.",
550
+ default="R0",
551
+ pdk=True,
552
+ ),
553
+ Variable(
554
+ "PAD_ROTATION_VERTICAL",
555
+ Optional[Literal["R0", "MY", "R90", "MXR90", "R180", "MX", "R270", "MYR90"]],
556
+ "Rotation to apply to the vertical sites to ensure pads are placed correctly.",
557
+ default="R0",
558
+ pdk=True,
559
+ ),
560
+ Variable(
561
+ "PAD_ROTATION_CORNER",
562
+ Optional[Literal["R0", "MY", "R90", "MXR90", "R180", "MX", "R270", "MYR90"]],
563
+ "Rotation to apply to the corner sites to ensure pads are placed correctly.",
564
+ default="R0",
565
+ pdk=True,
566
+ ),
538
567
  ]
539
568
 
540
569
  flow_common_variables = pdk_variables + scl_variables + option_variables + pad_variables
@@ -203,9 +203,9 @@ def migrate_old_config(config: Mapping[str, Any]) -> Dict[str, Any]:
203
203
  corner = f"*_{pvt}"
204
204
  lib_sta[corner] = lib_list
205
205
 
206
- if (
207
- new["PDK"].startswith("sky130") or new["PDK"].startswith("gf180mcu")
208
- ) and "LIB" not in config:
206
+ if (new["PDK"].startswith("sky130") or new["PDK"].startswith("gf180mcu")) and (
207
+ "LIB" not in config and "CELL_LIBS" not in config
208
+ ):
209
209
  process_sta("LIB_SYNTH")
210
210
  process_sta("LIB_SLOWEST")
211
211
  process_sta("LIB_FASTEST")
@@ -0,0 +1,3 @@
1
+ sky130: 74c0e6b118a67d94c24172143d3bd597473fa63d
2
+ gf180mcu: b344c97eacc2aaf8e14ae7e43e2e9dc0871de2c0
3
+ ihp-sg13g2: c4b8b4e5e7a05f375cca3815d51b3a37721fbf5c
@@ -56,34 +56,37 @@ proc read_pad_lef {} {
56
56
  }
57
57
  }
58
58
 
59
- proc read_pdk_gds {} {
60
- set old_rescale [gds rescale]
61
- set old_readonly [gds readonly]
59
+ proc _read_gds {env_name} {
60
+ # Pre-check
61
+ if { ![info exist ::env($env_name)] } {
62
+ return
63
+ }
64
+
65
+ # Save options
66
+ set old [list]
67
+ lappend old [gds rescale]
68
+ lappend old [gds readonly]
62
69
  gds rescale false
63
70
  gds readonly true
64
- set gds_files_in $::env(CELL_GDS)
71
+
72
+ # Read GDS
73
+ set gds_files_in $::env($env_name)
65
74
  foreach gds_file $gds_files_in {
66
75
  puts "> gds read $gds_file"
67
76
  gds read $gds_file
68
77
  }
69
- gds rescale $old_rescale
70
- gds readonly $old_readonly
78
+
79
+ # Restore options
80
+ gds rescale [lindex $old 0]
81
+ gds readonly [lindex $old 1]
82
+ }
83
+
84
+ proc read_pdk_gds {} {
85
+ _read_gds CELL_GDS
71
86
  }
72
87
 
73
88
  proc read_macro_gds {} {
74
- set old_rescale [gds rescale]
75
- set old_readonly [gds readonly]
76
- gds rescale false
77
- gds readonly true
78
- if { [info exist ::env(MACRO_GDS_FILES)] } {
79
- set gds_files_in $::env(MACRO_GDS_FILES)
80
- foreach gds_file $gds_files_in {
81
- puts "> gds read $gds_file"
82
- gds read $gds_file
83
- }
84
- }
85
- gds rescale $old_rescale
86
- gds readonly $old_readonly
89
+ _read_gds MACRO_GDS_FILES
87
90
  }
88
91
 
89
92
  proc read_macro_gds_blackbox {} {
@@ -104,35 +107,11 @@ proc read_macro_gds_blackbox {} {
104
107
  }
105
108
 
106
109
  proc read_extra_gds {} {
107
- set old_rescale [gds rescale]
108
- set old_readonly [gds readonly]
109
- gds rescale false
110
- gds readonly true
111
- if { [info exist ::env(EXTRA_GDS)] } {
112
- set gds_files_in $::env(EXTRA_GDS)
113
- foreach gds_file $gds_files_in {
114
- puts "> gds read $gds_file"
115
- gds read $gds_file
116
- }
117
- }
118
- gds rescale $old_rescale
119
- gds readonly $old_readonly
110
+ _read_gds EXTRA_GDS
120
111
  }
121
112
 
122
113
  proc read_pad_gds {} {
123
- set old_rescale [gds rescale]
124
- set old_readonly [gds readonly]
125
- gds rescale false
126
- gds readonly true
127
- if { [info exist ::env(PAD_GDS)] } {
128
- set gds_files_in $::env(PAD_GDS)
129
- foreach gds_file $gds_files_in {
130
- puts "> gds read $gds_file"
131
- gds read $gds_file
132
- }
133
- }
134
- gds rescale $old_rescale
135
- gds readonly $old_readonly
114
+ _read_gds PAD_GDS
136
115
  }
137
116
 
138
117
  proc read_def {} {
@@ -33,6 +33,10 @@ if { [info exists ::env(MAGIC_DRC_MAGLEFS)] } {
33
33
  gds noduplicates true
34
34
  gds readonly true
35
35
 
36
+ # Enable maskhints so that DRC rules against generated layers are run
37
+ # against the closest possible version to what's actually in the GDS
38
+ gds maskhints true
39
+
36
40
  # Flatten cells
37
41
  if { [info exists ::env(MAGIC_GDS_FLATGLOB)] } {
38
42
  foreach {gds_flatglob} $::env(MAGIC_GDS_FLATGLOB) {
@@ -52,8 +52,15 @@ class Design(object):
52
52
  netname_by_bit = {}
53
53
 
54
54
  for netname, info in yosys_design_object["netnames"].items():
55
- for bit in info["bits"]:
56
- netname_by_bit[bit] = netname
55
+ assert len(info["bits"]) > 0
56
+ # Single bit net, return name directly
57
+ if len(info["bits"]) == 1:
58
+ netname_by_bit[info["bits"][0]] = netname
59
+ # Append bit index to signal name
60
+ else:
61
+ offset = info.get("offset", 0)
62
+ for index, bit in enumerate(info["bits"]):
63
+ netname_by_bit[bit] = f"{netname}[{offset + index}]"
57
64
 
58
65
  self.verilog_net_names_by_bit_by_module[top_module] = netname_by_bit
59
66
  return self.verilog_net_names_by_bit_by_module[top_module][target_bit]
@@ -235,13 +235,6 @@ proc read_timing_info {args} {
235
235
  read_liberty -corner $corner_name $extra_lib
236
236
  }
237
237
  }
238
-
239
- if { [info exists ::env(PAD_LIBS) ] } {
240
- foreach lib $::env(PAD_LIBS) {
241
- puts "Reading gpio pad timing for the '$corner_name' corner at '$lib'…"
242
- read_liberty -corner $corner_name $lib
243
- }
244
- }
245
238
 
246
239
  set blackbox_wildcard {/// sta-blackbox}
247
240
  foreach nl $::env(_CURRENT_CORNER_NETLISTS) {
@@ -343,13 +336,6 @@ proc read_pnr_libs {args} {
343
336
  read_liberty -corner $corner_name $extra_lib
344
337
  }
345
338
  }
346
-
347
- if { [info exists ::env(PAD_LIBS) ] } {
348
- foreach pad_lib $::env(PAD_LIBS) {
349
- puts "Reading gpio pad timing library for the '$corner_name' corner at '$pad_lib'…"
350
- read_liberty -corner $corner_name $pad_lib
351
- }
352
- }
353
339
  }
354
340
  }
355
341
 
@@ -20,6 +20,11 @@ puts "\[INFO\] Generating padring…"
20
20
  set block [ord::get_db_block]
21
21
  set units [$block getDefUnits]
22
22
 
23
+ # Round a micrometer value to nanometer
24
+ proc round_um_nm {value} {
25
+ return [expr double(round($value * 1000)) / 1000]
26
+ }
27
+
23
28
  # Pad Placement Algorithm
24
29
  #
25
30
  # For all sides:
@@ -74,7 +79,10 @@ make_io_sites \
74
79
  -horizontal_site $::env(PAD_SITE_NAME) \
75
80
  -vertical_site $::env(PAD_SITE_NAME) \
76
81
  -corner_site $::env(PAD_CORNER_SITE_NAME) \
77
- -offset $::env(PAD_EDGE_SPACING)
82
+ -offset $::env(PAD_EDGE_SPACING) \
83
+ -rotation_horizontal $::env(PAD_ROTATION_HORIZONTAL) \
84
+ -rotation_vertical $::env(PAD_ROTATION_VERTICAL) \
85
+ -rotation_corner $::env(PAD_ROTATION_CORNER)
78
86
 
79
87
  set sides {PAD_SOUTH PAD_EAST PAD_NORTH PAD_WEST}
80
88
  set vertical_sides [list PAD_EAST PAD_WEST]
@@ -125,15 +133,15 @@ foreach side $sides {
125
133
 
126
134
  set space_between_pads [expr $space_for_fill / ([llength $::env($side)] + 1)]
127
135
  puts "space_between_pads: $space_between_pads"
128
-
129
- # Round to minimum site width (min. filler)
130
- set space_between_pads_min_filler [expr round(floor($space_between_pads / $pad_site_width) * $pad_site_width * 1000) / 1000]
131
- puts "space_between_pads_min_filler: $space_between_pads_min_filler"
136
+
137
+ # Round to PAD_SPACING_MULTIPLE
138
+ set space_between_pads_multiple [round_um_nm [expr floor($space_between_pads / $::env(PAD_SPACING_MULTIPLE)) * $::env(PAD_SPACING_MULTIPLE)]]
139
+ puts "space_between_pads_multiple: $space_between_pads_multiple"
132
140
 
133
141
  # The spacing for the pads on the side (the remaining space)
134
- set space_side [expr round(($space_for_fill - $space_between_pads_min_filler * ([llength $::env($side)] - 1)) / 2 * 1000) / 1000]
142
+ set space_side [round_um_nm [expr ($space_for_fill - $space_between_pads_multiple * ([llength $::env($side)] - 1)) / 2]]
135
143
 
136
- if { $space_side != round(floor($space_side / $pad_site_width) * $pad_site_width * 1000) / 1000 } {
144
+ if { $space_side != [round_um_nm [expr floor($space_side / $pad_site_width) * $pad_site_width]] } {
137
145
  puts "\[Error\] The remaining area for the pads on the side ($space_side) is not divisible by the minimum site width (minimum filler: $pad_site_width)."
138
146
  exit 1
139
147
  }
@@ -150,7 +158,7 @@ foreach side $sides {
150
158
  # For all instances
151
159
  foreach inst_name $::env($side) {
152
160
  if { [set inst [$block findInst $inst_name]] == "NULL" } {
153
- puts stderr "\[ERROR\] No instance $instance_name found."
161
+ puts stderr "\[ERROR\] No instance $inst_name found."
154
162
  exit 1
155
163
  }
156
164
  set master_name [[$inst getMaster] getName]
@@ -163,7 +171,7 @@ foreach side $sides {
163
171
  place_pad -row [dict get $row_names $side] -location $cur_pos $inst_name -master $master_name
164
172
 
165
173
  # Increment current position
166
- set cur_pos [expr $cur_pos + $space_between_pads_min_filler + $width]
174
+ set cur_pos [expr $cur_pos + $space_between_pads_multiple + $width]
167
175
  }
168
176
  }
169
177
 
@@ -175,10 +183,18 @@ place_corners $::env(PAD_CORNER)
175
183
  puts "\[INFO\] Placing filler cells…"
176
184
 
177
185
  # Place filler cells
178
- place_io_fill -row IO_NORTH {*}$::env(PAD_FILLERS)
179
- place_io_fill -row IO_SOUTH {*}$::env(PAD_FILLERS)
180
- place_io_fill -row IO_WEST {*}$::env(PAD_FILLERS)
181
- place_io_fill -row IO_EAST {*}$::env(PAD_FILLERS)
186
+ if {!$::env(PAD_TRIM_ROWS) || ($::env(PAD_NORTH) ne "")} { place_io_fill -row IO_NORTH {*}$::env(PAD_FILLERS) }
187
+ if {!$::env(PAD_TRIM_ROWS) || ($::env(PAD_SOUTH) ne "")} { place_io_fill -row IO_SOUTH {*}$::env(PAD_FILLERS) }
188
+ if {!$::env(PAD_TRIM_ROWS) || ($::env(PAD_WEST) ne "")} { place_io_fill -row IO_WEST {*}$::env(PAD_FILLERS) }
189
+ if {!$::env(PAD_TRIM_ROWS) || ($::env(PAD_EAST) ne "")} { place_io_fill -row IO_EAST {*}$::env(PAD_FILLERS) }
190
+
191
+ puts "\[INFO\] Deleting corner cells (if required)…"
192
+
193
+ # Delete corner cells if required
194
+ if {$::env(PAD_TRIM_ROWS) && ($::env(PAD_NORTH) eq "") && ($::env(PAD_WEST) eq "")} { odb::dbInst_destroy [$block findInst IO_CORNER_NORTH_WEST_INST] }
195
+ if {$::env(PAD_TRIM_ROWS) && ($::env(PAD_NORTH) eq "") && ($::env(PAD_EAST) eq "")} { odb::dbInst_destroy [$block findInst IO_CORNER_NORTH_EAST_INST] }
196
+ if {$::env(PAD_TRIM_ROWS) && ($::env(PAD_SOUTH) eq "") && ($::env(PAD_WEST) eq "")} { odb::dbInst_destroy [$block findInst IO_CORNER_SOUTH_WEST_INST] }
197
+ if {$::env(PAD_TRIM_ROWS) && ($::env(PAD_SOUTH) eq "") && ($::env(PAD_EAST) eq "")} { odb::dbInst_destroy [$block findInst IO_CORNER_SOUTH_EAST_INST] }
182
198
 
183
199
  puts "\[INFO\] Connecting ring signals…"
184
200
 
@@ -243,3 +259,4 @@ if { [info exists ::env(PAD_PLACE_IO_TERMINALS)] } {
243
259
  # Remove io rows to avoid causing confusion with the other tools
244
260
  puts "\[INFO\] Removing I/O rows…"
245
261
  remove_io_rows
262
+
@@ -139,6 +139,7 @@ if { $::env(PDN_CORE_RING) == 1 } {
139
139
  append_if_flag arg_list PDN_CORE_RING_ALLOW_OUT_OF_DIE -allow_out_of_die
140
140
  append_if_flag arg_list PDN_CORE_RING_CONNECT_TO_PADS -connect_to_pads
141
141
  append_if_equals arg_list PDN_EXTEND_TO "boundary" -extend_to_boundary
142
+ append_if_exists_argument arg_list PDN_CORE_RING_CONNECT_TO_PAD_LAYERS -connect_to_pad_layers
142
143
 
143
144
  set pdn_core_vertical_layer $::env(PDN_VERTICAL_LAYER)
144
145
  set pdn_core_horizontal_layer $::env(PDN_HORIZONTAL_LAYER)
@@ -33,12 +33,15 @@ if { $::env(DESIGN_REPAIR_REMOVE_BUFFERS) } {
33
33
  remove_buffers
34
34
  }
35
35
 
36
+ # Use SYNTH_BUFFER_CELL as buffer, since OpenROAD may select a hold/delay buffer
37
+ # See: https://github.com/librelane/librelane/pull/961
38
+
36
39
  if { $::env(DESIGN_REPAIR_BUFFER_INPUT_PORTS) } {
37
- buffer_ports -inputs
40
+ buffer_ports -inputs -buffer_cell [lindex [split $::env(SYNTH_BUFFER_CELL) "/"] 0]
38
41
  }
39
42
 
40
43
  if { $::env(DESIGN_REPAIR_BUFFER_OUTPUT_PORTS) } {
41
- buffer_ports -outputs
44
+ buffer_ports -outputs -buffer_cell [lindex [split $::env(SYNTH_BUFFER_CELL) "/"] 0]
42
45
  }
43
46
 
44
47
  set arg_list [list]
@@ -43,6 +43,11 @@ def json_header(
43
43
  "__librelane__",
44
44
  "__pnr__",
45
45
  ]
46
+ + (
47
+ [f"PAD_{config['PAD_CELL_LIBRARY']}"]
48
+ if "PAD_CELL_LIBRARY" in config
49
+ else []
50
+ )
46
51
  + (
47
52
  []
48
53
  if config.get("VERILOG_POWER_DEFINE") is None
@@ -157,6 +157,7 @@ def librelane_synth(
157
157
  ):
158
158
 
159
159
  d.run_pass("hierarchy", "-check", "-top", top, "-nokeep_prints", "-nokeep_asserts")
160
+ d.run_pass("chformal", "-remove")
160
161
  librelane_proc(d, report_dir)
161
162
 
162
163
  if keep_hierarchy_min_cost:
@@ -251,12 +252,20 @@ def synthesize(
251
252
  extra = json.load(open(extra_in))
252
253
 
253
254
  includes = config.get("VERILOG_INCLUDE_DIRS") or []
254
- defines = (config.get("VERILOG_DEFINES") or []) + [
255
- f"PDK_{config['PDK'].replace('-','_')}",
256
- f"SCL_{config['STD_CELL_LIBRARY']}",
257
- "__librelane__",
258
- "__pnr__",
259
- ]
255
+ defines = (
256
+ (config.get("VERILOG_DEFINES") or [])
257
+ + [
258
+ f"PDK_{config['PDK'].replace('-','_')}",
259
+ f"SCL_{config['STD_CELL_LIBRARY']}",
260
+ "__librelane__",
261
+ "__pnr__",
262
+ ]
263
+ + (
264
+ [f"PAD_{config['PAD_CELL_LIBRARY']}"]
265
+ if "PAD_CELL_LIBRARY" in config
266
+ else []
267
+ )
268
+ )
260
269
 
261
270
  blackbox_models = extra["blackbox_models"]
262
271
  libs = extra["libs_synth"]
@@ -263,6 +263,12 @@ pdn_variables = [
263
263
  default=False,
264
264
  pdk=True,
265
265
  ),
266
+ Variable(
267
+ "PDN_CORE_RING_CONNECT_TO_PAD_LAYERS",
268
+ Optional[List[str]],
269
+ "Restrict the pad pins layers to this list.",
270
+ pdk=True,
271
+ ),
266
272
  Variable(
267
273
  "PDN_CORE_RING_ALLOW_OUT_OF_DIE",
268
274
  bool,
@@ -171,7 +171,7 @@ class Render(KLayoutStep):
171
171
  id = "KLayout.Render"
172
172
  name = "Render Image (w/ KLayout)"
173
173
 
174
- inputs = [DesignFormat.DEF]
174
+ inputs = []
175
175
  outputs = []
176
176
 
177
177
  config_vars = KLayoutStep.config_vars + [
@@ -216,10 +216,14 @@ class Render(KLayoutStep):
216
216
  def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]:
217
217
  views_updates: ViewsUpdate = {}
218
218
 
219
- input_view = state_in[DesignFormat.DEF]
219
+ input_view = state_in.get(DesignFormat.DEF)
220
+
220
221
  if gds := state_in.get(DesignFormat.GDS):
221
222
  input_view = gds
222
223
 
224
+ if input_view is None:
225
+ raise StepError(f"{id} requires at least one of LEF or GDS as input.")
226
+
223
227
  assert isinstance(input_view, Path)
224
228
 
225
229
  klayout_render = os.path.join(
@@ -434,7 +438,7 @@ class DRC(KLayoutStep):
434
438
  Unlike most steps, the KLayout scripts vary quite wildly by PDK. If a PDK
435
439
  is not supported by this step, it will simply be skipped.
436
440
 
437
- Currently, only sky130A and sky130B are supported.
441
+ Currently, sky130, gf180mcu and ihp-sg13 are supported.
438
442
  """
439
443
 
440
444
  id = "KLayout.DRC"
@@ -455,7 +459,7 @@ class DRC(KLayoutStep):
455
459
  ),
456
460
  Variable(
457
461
  "KLAYOUT_DRC_OPTIONS",
458
- Optional[Dict[str, Union[bool, int, str]]],
462
+ Optional[Dict[str, Union[int, bool, str]]],
459
463
  "Options passed directly to the KLayout DRC runset. They vary from one PDK to another.",
460
464
  pdk=True,
461
465
  ),
@@ -513,9 +517,6 @@ class DRC(KLayoutStep):
513
517
  if threads != "1":
514
518
  opts.extend(
515
519
  [
516
- "-rd",
517
- f"thr={threads}",
518
- # Use "threads" if possible
519
520
  "-rd",
520
521
  f"threads={threads}",
521
522
  ]
@@ -602,6 +603,8 @@ class DRC(KLayoutStep):
602
603
  "-rd",
603
604
  f"seal={seal}",
604
605
  "-rd",
606
+ f"thr={threads}",
607
+ "-rd",
605
608
  f"threads={threads}",
606
609
  ],
607
610
  env=env,
@@ -658,7 +661,7 @@ class DRC(KLayoutStep):
658
661
  opts.extend(
659
662
  [
660
663
  "-rd",
661
- f"thr={threads}",
664
+ f"threads={threads}",
662
665
  ]
663
666
  )
664
667
 
@@ -727,7 +730,7 @@ class DRC(KLayoutStep):
727
730
  opts.extend(
728
731
  [
729
732
  "-rd",
730
- f"thr={threads}",
733
+ f"threads={threads}",
731
734
  ]
732
735
  )
733
736
 
@@ -972,7 +972,8 @@ class CellFrequencyTables(OdbpyStep):
972
972
  kwargs, env = self.extract_env(kwargs)
973
973
 
974
974
  env_copy = env.copy()
975
- lib_list = self.toolbox.filter_views(self.config, self.config["LIB"])
975
+ lib_list = self.toolbox.filter_views(self.config, self.config["CELL_LIBS"])
976
+ lib_list += self.toolbox.filter_views(self.config, self.config["PAD_LIBS"])
976
977
  env_copy["_PNR_LIBS"] = TclStep.value_to_tcl(lib_list)
977
978
  super().run_subprocess(
978
979
  [
@@ -317,7 +317,8 @@ class OpenROADStep(TclStep):
317
317
  def prepare_env(self, env: dict, state: State) -> dict:
318
318
  env = super().prepare_env(env, state)
319
319
 
320
- lib_list = self.toolbox.filter_views(self.config, self.config["LIB"])
320
+ lib_list = self.toolbox.filter_views(self.config, self.config["CELL_LIBS"])
321
+ lib_list += self.toolbox.filter_views(self.config, self.config["PAD_LIBS"])
321
322
  lib_list += self.toolbox.get_macro_views(self.config, DesignFormat.LIB)
322
323
 
323
324
  env["_SDC_IN"] = self.config["PNR_SDC_FILE"] or self.config["FALLBACK_SDC"]
@@ -1266,6 +1267,19 @@ class PadRing(OpenROADStep):
1266
1267
  Optional[List[str]],
1267
1268
  "The pad instance names for the west pad row.",
1268
1269
  ),
1270
+ Variable(
1271
+ "PAD_SPACING_MULTIPLE",
1272
+ Decimal,
1273
+ "The spacing between the pad cells will be a multiple of this value. Please ensure that the remaining space on the sides is divisible by the minimum site width.",
1274
+ default=1,
1275
+ units="µm",
1276
+ ),
1277
+ Variable(
1278
+ "PAD_TRIM_ROWS",
1279
+ bool,
1280
+ "If any of `PAD_[SOUTH|EAST|NORTH|WEST]` is empty, skip io fill for those rows and delete the corners with two neighbouring empty rows.",
1281
+ default=False,
1282
+ ),
1269
1283
  ]
1270
1284
 
1271
1285
  def get_script_path(self):
@@ -2239,7 +2253,8 @@ class IRDropReport(OpenROADStep):
2239
2253
  elif len(spefs_in) < 1:
2240
2254
  raise StepException("No SPEF file found for the default corner.")
2241
2255
 
2242
- libs_in = self.toolbox.filter_views(self.config, self.config["LIB"])
2256
+ libs_in = self.toolbox.filter_views(self.config, self.config["CELL_LIBS"])
2257
+ libs_in += self.toolbox.filter_views(self.config, self.config["PAD_LIBS"])
2243
2258
 
2244
2259
  if self.config["VSRC_LOC_FILES"] is None:
2245
2260
  self.warn(