librelane 2.4.0.dev2__tar.gz → 2.4.0.dev3__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 (169) hide show
  1. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/PKG-INFO +1 -1
  2. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/variable.py +12 -7
  3. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/defutil.py +6 -7
  4. librelane-2.4.0.dev3/librelane/scripts/odbpy/eco_buffer.py +181 -0
  5. librelane-2.4.0.dev3/librelane/scripts/odbpy/eco_diode.py +139 -0
  6. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/reader.py +15 -11
  7. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/io.tcl +66 -2
  8. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/__init__.py +1 -1
  9. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/odb.py +160 -24
  10. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/openroad.py +7 -2
  11. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/pyproject.toml +1 -1
  12. librelane-2.4.0.dev2/librelane/scripts/odbpy/exception_codes.py +0 -17
  13. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/Readme.md +0 -0
  14. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/__init__.py +0 -0
  15. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/__main__.py +0 -0
  16. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/__version__.py +0 -0
  17. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/__init__.py +0 -0
  18. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/cli.py +0 -0
  19. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/drc.py +0 -0
  20. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/generic_dict.py +0 -0
  21. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/metrics/__init__.py +0 -0
  22. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/metrics/__main__.py +0 -0
  23. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/metrics/library.py +0 -0
  24. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/metrics/metric.py +0 -0
  25. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/metrics/util.py +0 -0
  26. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/misc.py +0 -0
  27. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/ring_buffer.py +0 -0
  28. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/tcl.py +0 -0
  29. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/toolbox.py +0 -0
  30. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/tpe.py +0 -0
  31. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/common/types.py +0 -0
  32. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/__init__.py +0 -0
  33. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/__main__.py +0 -0
  34. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/config.py +0 -0
  35. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/flow.py +0 -0
  36. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/pdk_compat.py +0 -0
  37. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/preprocessor.py +0 -0
  38. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/config/removals.py +0 -0
  39. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/container.py +0 -0
  40. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/env_info.py +0 -0
  41. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm/config.yaml +0 -0
  42. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm/pin_order.cfg +0 -0
  43. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm/src/impl.sdc +0 -0
  44. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm/src/signoff.sdc +0 -0
  45. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm/src/spm.v +0 -0
  46. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm/verify/spm_tb.v +0 -0
  47. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm-user_project_wrapper/SPM_example.v +0 -0
  48. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm-user_project_wrapper/base_sdc_file.sdc +0 -0
  49. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm-user_project_wrapper/config-tut.json +0 -0
  50. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm-user_project_wrapper/config.json +0 -0
  51. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm-user_project_wrapper/defines.v +0 -0
  52. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm-user_project_wrapper/template.def +0 -0
  53. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/examples/spm-user_project_wrapper/user_project_wrapper.v +0 -0
  54. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/__init__.py +0 -0
  55. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/builtins.py +0 -0
  56. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/classic.py +0 -0
  57. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/cli.py +0 -0
  58. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/flow.py +0 -0
  59. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/misc.py +0 -0
  60. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/optimizing.py +0 -0
  61. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/sequential.py +0 -0
  62. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/flows/synth_explore.py +0 -0
  63. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/logging/__init__.py +0 -0
  64. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/logging/logger.py +0 -0
  65. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/open_pdks_rev +0 -0
  66. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/plugins.py +0 -0
  67. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/py.typed +0 -0
  68. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/base.sdc +0 -0
  69. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/klayout/Readme.md +0 -0
  70. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/klayout/open_design.py +0 -0
  71. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/klayout/render.py +0 -0
  72. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/klayout/stream_out.py +0 -0
  73. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/klayout/xml_drc_report_to_json.py +0 -0
  74. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/klayout/xor.drc +0 -0
  75. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/Readme.md +0 -0
  76. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/common/read.tcl +0 -0
  77. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/def/antenna_check.tcl +0 -0
  78. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/def/mag.tcl +0 -0
  79. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/def/mag_gds.tcl +0 -0
  80. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/drc.tcl +0 -0
  81. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/extract_spice.tcl +0 -0
  82. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/gds/drc_batch.tcl +0 -0
  83. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/gds/erase_box.tcl +0 -0
  84. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/gds/extras_mag.tcl +0 -0
  85. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/gds/mag_with_pointers.tcl +0 -0
  86. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/get_bbox.tcl +0 -0
  87. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/lef/extras_maglef.tcl +0 -0
  88. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/lef/maglef.tcl +0 -0
  89. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/lef.tcl +0 -0
  90. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/open.tcl +0 -0
  91. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/magic/wrapper.tcl +0 -0
  92. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/netgen/setup.tcl +0 -0
  93. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/apply_def_template.py +0 -0
  94. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/cell_frequency.py +0 -0
  95. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/check_antenna_properties.py +0 -0
  96. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/contextualize.py +0 -0
  97. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/diodes.py +0 -0
  98. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/disconnected_pins.py +0 -0
  99. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/filter_unannotated.py +0 -0
  100. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/io_place.py +0 -0
  101. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/ioplace_parser/__init__.py +0 -0
  102. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/ioplace_parser/parse.py +0 -0
  103. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/label_macro_pins.py +0 -0
  104. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/lefutil.py +0 -0
  105. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/placers.py +0 -0
  106. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/power_utils.py +0 -0
  107. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/random_place.py +0 -0
  108. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/remove_buffers.py +0 -0
  109. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/snap_to_grid.py +0 -0
  110. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/odbpy/wire_lengths.py +0 -0
  111. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/antenna_check.tcl +0 -0
  112. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/antenna_repair.tcl +0 -0
  113. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/basic_mp.tcl +0 -0
  114. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/buffer_list.tcl +0 -0
  115. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/dpl.tcl +0 -0
  116. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/dpl_cell_pad.tcl +0 -0
  117. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/grt.tcl +0 -0
  118. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/pdn_cfg.tcl +0 -0
  119. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/resizer.tcl +0 -0
  120. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/set_global_connections.tcl +0 -0
  121. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/set_layer_adjustments.tcl +0 -0
  122. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/set_power_nets.tcl +0 -0
  123. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/set_rc.tcl +0 -0
  124. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/common/set_routing_layers.tcl +0 -0
  125. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/cts.tcl +0 -0
  126. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/cut_rows.tcl +0 -0
  127. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/dpl.tcl +0 -0
  128. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/drt.tcl +0 -0
  129. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/fill.tcl +0 -0
  130. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/floorplan.tcl +0 -0
  131. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/gpl.tcl +0 -0
  132. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/grt.tcl +0 -0
  133. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/gui.tcl +0 -0
  134. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/insert_buffer.tcl +0 -0
  135. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/ioplacer.tcl +0 -0
  136. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/irdrop.tcl +0 -0
  137. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/pdn.tcl +0 -0
  138. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/rcx.tcl +0 -0
  139. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/repair_design.tcl +0 -0
  140. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/repair_design_postgrt.tcl +0 -0
  141. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/rsz_timing_postcts.tcl +0 -0
  142. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/rsz_timing_postgrt.tcl +0 -0
  143. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/sta/check_macro_instances.tcl +0 -0
  144. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/sta/corner.tcl +0 -0
  145. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/tapcell.tcl +0 -0
  146. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/openroad/write_views.tcl +0 -0
  147. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/pyosys/construct_abc_script.py +0 -0
  148. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/pyosys/json_header.py +0 -0
  149. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/pyosys/synthesize.py +0 -0
  150. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/pyosys/ys_common.py +0 -0
  151. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/scripts/tclsh/hello.tcl +0 -0
  152. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/state/__init__.py +0 -0
  153. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/state/__main__.py +0 -0
  154. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/state/design_format.py +0 -0
  155. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/state/state.py +0 -0
  156. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/__main__.py +0 -0
  157. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/checker.py +0 -0
  158. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/common_variables.py +0 -0
  159. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/cvc_rv.py +0 -0
  160. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/klayout.py +0 -0
  161. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/magic.py +0 -0
  162. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/misc.py +0 -0
  163. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/netgen.py +0 -0
  164. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/openroad_alerts.py +0 -0
  165. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/pyosys.py +0 -0
  166. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/step.py +0 -0
  167. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/tclstep.py +0 -0
  168. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/verilator.py +0 -0
  169. {librelane-2.4.0.dev2 → librelane-2.4.0.dev3}/librelane/steps/yosys.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: librelane
3
- Version: 2.4.0.dev2
3
+ Version: 2.4.0.dev3
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
@@ -238,7 +238,7 @@ def some_of(t: Type[Any]) -> Type[Any]:
238
238
  return new_union # type: ignore
239
239
 
240
240
 
241
- def repr_type(t: Type[Any]) -> str: # pragma: no cover
241
+ def repr_type(t: Type[Any], for_document: bool = False) -> str: # pragma: no cover
242
242
  optional = is_optional(t)
243
243
  some = some_of(t)
244
244
 
@@ -247,18 +247,25 @@ def repr_type(t: Type[Any]) -> str: # pragma: no cover
247
247
  else:
248
248
  type_string = str(some)
249
249
 
250
+ if is_dataclass(t):
251
+ type_string = (
252
+ f"{{class}}`{some.__qualname__} <{some.__module__}.{some.__qualname__}>`"
253
+ )
254
+
255
+ separator = "|<br />" if for_document else "|"
256
+
250
257
  if inspect.isclass(some) and issubclass(some, Enum):
251
- type_string = "|".join([str(e.name) for e in some])
258
+ type_string = separator.join([str(e.name) for e in some])
252
259
  type_string = f"`{type_string}`"
253
260
  else:
254
261
  origin, args = get_origin(some), get_args(some)
255
262
  if origin is not None:
256
263
  if origin == Union:
257
264
  arg_strings = [repr_type(arg) for arg in args]
258
- type_string = "|".join(arg_strings)
265
+ type_string = separator.join(arg_strings)
259
266
  type_string = f"({type_string})"
260
267
  elif origin == Literal:
261
- return "|".join([repr(arg) for arg in args])
268
+ return separator.join([repr(arg) for arg in args])
262
269
  else:
263
270
  arg_strings = [repr_type(arg) for arg in args]
264
271
  type_string = f"{type_string}[{', '.join(arg_strings)}]"
@@ -377,9 +384,7 @@ class Variable:
377
384
  for easier wrapping by web browsers/PDF renderers/what have you
378
385
  :returns: A pretty Markdown string representation of the Variable's type.
379
386
  """
380
- if for_document:
381
- return repr_type(self.type).replace("|", "|<br />")
382
- return repr_type(self.type)
387
+ return repr_type(self.type, for_document=for_document)
383
388
 
384
389
  def desc_repr_md(self) -> str: # pragma: no cover
385
390
  """
@@ -21,7 +21,6 @@ from decimal import Decimal
21
21
 
22
22
  from reader import click_odb, click
23
23
  from typing import Tuple, List
24
- from exception_codes import METAL_LAYER_ERROR, FORMAT_ERROR, NOT_FOUND_ERROR
25
24
 
26
25
 
27
26
  @click.group()
@@ -481,7 +480,7 @@ def parse_obstructions(obstructions) -> List[Tuple[str, List[int]]]:
481
480
  f"[ERROR] Incorrectly formatted input {obs}.\n Format: layer llx lly urx ury, ...",
482
481
  file=sys.stderr,
483
482
  )
484
- sys.exit(FORMAT_ERROR)
483
+ sys.exit(1)
485
484
  else:
486
485
  layer = m.group("layer")
487
486
  bbox = [Decimal(x) for x in m.group("bbox").split()]
@@ -505,8 +504,8 @@ def add_obstructions(reader, input_lefs, obstructions):
505
504
  layer = obs[0]
506
505
  odb_layer = reader.tech.findLayer(layer)
507
506
  if odb_layer is None:
508
- print(f"[ERROR] layer {layer} doesn't exist.", file=sys.stderr)
509
- sys.exit(METAL_LAYER_ERROR)
507
+ print(f"[ERROR] Layer '{layer}' not found.", file=sys.stderr)
508
+ sys.exit(1)
510
509
  bbox = obs[1]
511
510
  dbu = reader.tech.getDbUnitsPerMicron()
512
511
  bbox = [int(x * dbu) for x in bbox]
@@ -550,8 +549,8 @@ def remove_obstructions(reader, input_lefs, obstructions):
550
549
  bbox = [int(x * dbu) for x in bbox] # To dbus
551
550
  found = False
552
551
  if reader.tech.findLayer(layer) is None:
553
- print(f"[ERROR] layer {layer} doesn't exist.", file=sys.stderr)
554
- sys.exit(METAL_LAYER_ERROR)
552
+ print(f"[ERROR] Layer '{layer}' not found.", file=sys.stderr)
553
+ sys.exit(1)
555
554
  for odb_obstruction in existing_obstructions:
556
555
  odb_layer, odb_bbox, odb_obj = odb_obstruction
557
556
  if (odb_layer, odb_bbox) == (layer, bbox):
@@ -565,7 +564,7 @@ def remove_obstructions(reader, input_lefs, obstructions):
565
564
  f"[ERROR] Obstruction on {layer} at {bbox} (DBU) not found.",
566
565
  file=sys.stderr,
567
566
  )
568
- sys.exit(NOT_FOUND_ERROR)
567
+ sys.exit(1)
569
568
 
570
569
 
571
570
  cli.add_command(remove_obstructions)
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2025 Efabless Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import sys
16
+ from reader import click_odb, click, odb
17
+ import grt as GRT
18
+
19
+
20
+ def average_location(instances):
21
+ locations = [instance.getLocation() for instance in instances]
22
+ x_sum = sum(loc[0] for loc in locations)
23
+ y_sum = sum(loc[1] for loc in locations)
24
+ return (x_sum // len(locations), y_sum // len(locations))
25
+
26
+
27
+ @click.command()
28
+ @click_odb
29
+ def cli(reader):
30
+ grt = reader.design.getGlobalRouter()
31
+ dpl = reader.design.getOpendp()
32
+
33
+ insts_to_temporarily_lock_then_unlock_later = []
34
+ for inst in reader.block.getInsts():
35
+ if inst.getPlacementStatus() != "LOCKED":
36
+ insts_to_temporarily_lock_then_unlock_later.append(
37
+ (inst, inst.getPlacementStatus())
38
+ )
39
+ inst.setPlacementStatus("LOCKED")
40
+
41
+ reader._grt_setup(grt)
42
+
43
+ grt_inc = GRT.IncrementalGRoute(grt, reader.block)
44
+ i = 0
45
+
46
+ for target_info in reader.config["INSERT_ECO_BUFFERS"]:
47
+ target_name, target_pin = target_info["target"].split("/")
48
+ name_escaped = reader.escape_verilog_name(target_name)
49
+ buffer_master = target_info["buffer"]
50
+
51
+ master = reader.db.findMaster(buffer_master)
52
+ if master is None:
53
+ print(
54
+ f"[ERROR] Buffer type '{buffer_master}' not found.",
55
+ file=sys.stderr,
56
+ )
57
+ exit(-1)
58
+
59
+ target = reader.block.findInst(name_escaped)
60
+ if target is None:
61
+ print(f"[ERROR] Instance '{target_name}' not found.", file=sys.stderr)
62
+ exit(-1)
63
+
64
+ target_iterm = target.findITerm(target_pin)
65
+ if target_iterm is None:
66
+ print(
67
+ f"[ERROR] Pin '{target_pin}' not found for instance '{target_name}'.",
68
+ file=sys.stderr,
69
+ )
70
+ exit(-1)
71
+
72
+ net = target_iterm.getNet()
73
+ if net is None:
74
+ print(
75
+ f"[ERROR] Net not found on pin '{target_pin}' of instance '{target_name}'.",
76
+ file=sys.stderr,
77
+ )
78
+ exit(-1)
79
+
80
+ new_buf_name = f"eco_buffer_{i}"
81
+ new_net_name = f"eco_buffer_{i}_net"
82
+ while (
83
+ reader.block.findInst(new_buf_name) is not None
84
+ or reader.block.findNet(new_net_name) is not None
85
+ ):
86
+ i += 1
87
+ new_buf_name = f"eco_buffer_{i}"
88
+ new_net_name = f"eco_buffer_{i}_net"
89
+
90
+ # Prepare buffer cell, net
91
+ eco_buffer = odb.dbInst.create(reader.block, master, new_buf_name)
92
+ eco_net = odb.dbNet.create(reader.block, new_net_name)
93
+ buffer_iterms = eco_buffer.getITerms()
94
+ buffer_a = None
95
+ for iterm in buffer_iterms:
96
+ if iterm.isInputSignal():
97
+ buffer_a = iterm
98
+ break # Exit loop once input is found
99
+ if buffer_a is None:
100
+ print(
101
+ f"[ERROR] Buffer {buffer_master} has no input signals.",
102
+ file=sys.stderr,
103
+ )
104
+ exit(-1)
105
+
106
+ buffer_x = None
107
+ for iterm in buffer_iterms:
108
+ if iterm.isOutputSignal():
109
+ buffer_x = iterm
110
+ break # Exit loop once output is found
111
+ if buffer_x is None:
112
+ print(
113
+ f"[ERROR] Buffer {buffer_master} has no output signals.",
114
+ file=sys.stderr,
115
+ )
116
+ exit(-1)
117
+
118
+ location_instances = [target]
119
+ net_iterms = net.getITerms()
120
+ if target_iterm.getIoType() == "INPUT":
121
+ driver_iterms = [
122
+ iterm for iterm in net_iterms if iterm.getIoType() in ["OUTPUT"]
123
+ ]
124
+ drivers = [iterm.getInst() for iterm in driver_iterms]
125
+ location_instances.extend(drivers)
126
+
127
+ target_iterm.disconnect()
128
+ buffer_a.connect(net)
129
+ buffer_x.connect(eco_net)
130
+ target_iterm.connect(eco_net)
131
+ elif target_iterm.getIoType() == "OUTPUT":
132
+ sink_iterms = [
133
+ iterm for iterm in net_iterms if iterm.getIoType() in ["INPUT", "INOUT"]
134
+ ]
135
+ sinks = [iterm.getInst() for iterm in sink_iterms]
136
+ location_instances.extend(sinks)
137
+
138
+ target_iterm.disconnect()
139
+ target_iterm.connect(eco_net)
140
+ buffer_a.connect(eco_net)
141
+ buffer_x.connect(net)
142
+ else:
143
+ print(
144
+ f"[ERROR] {target_name}/{target_pin} is neither an INPUT or an OUTPUT and is unsupported by this script. To buffer an INOUT port, buffer its drivers instead.",
145
+ file=sys.stderr,
146
+ )
147
+ exit(-1)
148
+
149
+ if target_info.get("placement") is not None:
150
+ eco_x, eco_y = target_info["placement"]
151
+ eco_x = reader.block.micronsToDbu(float(eco_x))
152
+ eco_y = reader.block.micronsToDbu(float(eco_y))
153
+ eco_loc = (eco_x, eco_y)
154
+ else:
155
+ eco_loc = average_location(location_instances)
156
+
157
+ eco_buffer.setOrient("R0")
158
+ eco_buffer.setLocation(*eco_loc)
159
+ eco_buffer.setPlacementStatus("PLACED")
160
+ grt.addDirtyNet(net)
161
+ grt.addDirtyNet(eco_net)
162
+
163
+ site = reader.rows[0].getSite()
164
+ max_disp_x = int(
165
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_X"])
166
+ / site.getWidth()
167
+ )
168
+ max_disp_y = int(
169
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_Y"])
170
+ / site.getHeight()
171
+ )
172
+ dpl.detailedPlacement(max_disp_x, max_disp_y)
173
+
174
+ grt_inc.updateRoutes(True)
175
+
176
+ for inst, previous_status in insts_to_temporarily_lock_then_unlock_later:
177
+ inst.setPlacementStatus(previous_status)
178
+
179
+
180
+ if __name__ == "__main__":
181
+ cli()
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2025 Efabless Corporation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import sys
16
+ from reader import click_odb, click, odb
17
+ import grt as GRT
18
+
19
+
20
+ @click.command()
21
+ @click_odb
22
+ def cli(reader):
23
+ grt = reader.design.getGlobalRouter()
24
+ dpl = reader.design.getOpendp()
25
+
26
+ insts_to_temporarily_lock_then_unlock_later = []
27
+ for inst in reader.block.getInsts():
28
+ if inst.getPlacementStatus() != "LOCKED":
29
+ insts_to_temporarily_lock_then_unlock_later.append(
30
+ (inst, inst.getPlacementStatus())
31
+ )
32
+ inst.setPlacementStatus("LOCKED")
33
+
34
+ reader._grt_setup(grt)
35
+
36
+ diode_master, diode_pin = reader.config["DIODE_CELL"].split("/")
37
+
38
+ # print(grt)
39
+ grt_inc = GRT.IncrementalGRoute(grt, reader.block)
40
+ i = 0
41
+ for target_info in reader.config["INSERT_ECO_DIODES"]:
42
+ target_name, target_pin = target_info["target"].split("/")
43
+ name_escaped = reader.escape_verilog_name(target_name)
44
+
45
+ target = reader.block.findInst(name_escaped)
46
+ if target is None:
47
+ print(
48
+ f"[ERROR] Instance '{target_name}' not found.",
49
+ file=sys.stderr,
50
+ )
51
+ exit(-1)
52
+
53
+ master = reader.db.findMaster(diode_master)
54
+ if master is None:
55
+ print(
56
+ f"[ERROR] Cell kind '{diode_master}' not found.",
57
+ file=sys.stderr,
58
+ )
59
+ exit(-1)
60
+
61
+ target_iterm = target.findITerm(target_pin)
62
+ if target_iterm is None:
63
+ print(
64
+ f"[ERROR] Pin '{target_pin}' not found for instance {target_name}.",
65
+ file=sys.stderr,
66
+ )
67
+ exit(-1)
68
+
69
+ if target_iterm.getIoType() not in ["INPUT", "INOUT"]:
70
+ print(
71
+ f"[ERROR] Pin {target_info['target']} is an OUTPUT pin.",
72
+ file=sys.stderr,
73
+ )
74
+ exit(-1)
75
+
76
+ net = target_iterm.getNet()
77
+ if net is None:
78
+ print(
79
+ f"[ERROR] Pin {target_info['target']} has no nets connected.",
80
+ file=sys.stderr,
81
+ )
82
+ exit(-1)
83
+
84
+ eco_diode_name = f"eco_diode_{i}"
85
+ while reader.block.findInst(eco_diode_name) is not None:
86
+ i += 1
87
+ eco_diode_name = f"eco_diode_{i}"
88
+
89
+ eco_diode = odb.dbInst.create(
90
+ reader.block,
91
+ master,
92
+ eco_diode_name,
93
+ )
94
+
95
+ diode_iterm = eco_diode.findITerm(diode_pin)
96
+ if diode_iterm is None:
97
+ print(
98
+ f"[ERROR] Pin '{diode_pin}' on ECO diode not found- invalid DIODE_CELL definition.",
99
+ file=sys.stderr,
100
+ )
101
+ exit(-1)
102
+
103
+ sys.stdout.flush()
104
+
105
+ if target_info["placement"] is not None:
106
+ x, y = target_info["placement"]
107
+ x = reader.block.micronsToDbu(float(x))
108
+ y = reader.block.micronsToDbu(float(y))
109
+ else:
110
+ x, y = target.getLocation()
111
+
112
+ eco_diode.setOrient("R0")
113
+ eco_diode.setLocation(x, y)
114
+ eco_diode.setPlacementStatus("PLACED")
115
+
116
+ diode_iterm.connect(net)
117
+ grt.addDirtyNet(net)
118
+
119
+ site = reader.rows[0].getSite()
120
+ max_disp_x = int(
121
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_X"])
122
+ / site.getWidth()
123
+ )
124
+ max_disp_y = int(
125
+ reader.design.micronToDBU(reader.config["PL_MAX_DISPLACEMENT_Y"])
126
+ / site.getHeight()
127
+ )
128
+ dpl.detailedPlacement(max_disp_x, max_disp_y)
129
+
130
+ grt_inc.updateRoutes(True)
131
+
132
+ for inst, previous_status in insts_to_temporarily_lock_then_unlock_later:
133
+ inst.setPlacementStatus(previous_status)
134
+
135
+ reader.design.writeDef("out.def")
136
+
137
+
138
+ if __name__ == "__main__":
139
+ cli()
@@ -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