siliconcompiler 0.35.3__py3-none-any.whl → 0.36.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc_issue.py +18 -2
  3. siliconcompiler/checklist.py +2 -1
  4. siliconcompiler/constraints/__init__.py +4 -1
  5. siliconcompiler/constraints/asic_component.py +49 -11
  6. siliconcompiler/constraints/asic_floorplan.py +23 -21
  7. siliconcompiler/constraints/asic_pins.py +55 -17
  8. siliconcompiler/constraints/asic_timing.py +280 -57
  9. siliconcompiler/constraints/fpga_timing.py +212 -18
  10. siliconcompiler/constraints/timing_mode.py +82 -0
  11. siliconcompiler/data/templates/replay/replay.sh.j2 +27 -14
  12. siliconcompiler/data/templates/tcl/manifest.tcl.j2 +0 -6
  13. siliconcompiler/flowgraph.py +95 -42
  14. siliconcompiler/flows/generate_openroad_rcx.py +2 -2
  15. siliconcompiler/flows/highresscreenshotflow.py +37 -0
  16. siliconcompiler/library.py +2 -1
  17. siliconcompiler/package/__init__.py +56 -51
  18. siliconcompiler/project.py +13 -2
  19. siliconcompiler/scheduler/docker.py +24 -25
  20. siliconcompiler/scheduler/scheduler.py +143 -100
  21. siliconcompiler/scheduler/schedulernode.py +138 -22
  22. siliconcompiler/scheduler/slurm.py +120 -35
  23. siliconcompiler/scheduler/taskscheduler.py +19 -23
  24. siliconcompiler/schema/_metadata.py +1 -1
  25. siliconcompiler/schema/editableschema.py +29 -0
  26. siliconcompiler/schema/namedschema.py +2 -4
  27. siliconcompiler/schema/parametervalue.py +14 -2
  28. siliconcompiler/schema_support/cmdlineschema.py +0 -3
  29. siliconcompiler/schema_support/dependencyschema.py +0 -6
  30. siliconcompiler/schema_support/option.py +82 -1
  31. siliconcompiler/schema_support/pathschema.py +7 -13
  32. siliconcompiler/schema_support/record.py +4 -3
  33. siliconcompiler/tool.py +105 -52
  34. siliconcompiler/tools/_common/tcl/sc_schema_access.tcl +0 -6
  35. siliconcompiler/tools/keplerformal/__init__.py +7 -0
  36. siliconcompiler/tools/keplerformal/lec.py +112 -0
  37. siliconcompiler/tools/klayout/__init__.py +3 -0
  38. siliconcompiler/tools/klayout/screenshot.py +66 -1
  39. siliconcompiler/tools/klayout/scripts/klayout_convert_drc_db.py +1 -0
  40. siliconcompiler/tools/klayout/scripts/klayout_export.py +11 -40
  41. siliconcompiler/tools/klayout/scripts/klayout_operations.py +1 -0
  42. siliconcompiler/tools/klayout/scripts/klayout_show.py +5 -4
  43. siliconcompiler/tools/klayout/scripts/klayout_utils.py +16 -5
  44. siliconcompiler/tools/montage/tile.py +26 -12
  45. siliconcompiler/tools/openroad/__init__.py +27 -1
  46. siliconcompiler/tools/openroad/_apr.py +107 -14
  47. siliconcompiler/tools/openroad/clock_tree_synthesis.py +1 -0
  48. siliconcompiler/tools/openroad/global_placement.py +1 -0
  49. siliconcompiler/tools/openroad/init_floorplan.py +119 -7
  50. siliconcompiler/tools/openroad/power_grid_analysis.py +174 -0
  51. siliconcompiler/tools/openroad/repair_design.py +1 -0
  52. siliconcompiler/tools/openroad/repair_timing.py +1 -0
  53. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +1 -1
  54. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +91 -18
  55. siliconcompiler/tools/openroad/scripts/apr/sc_irdrop.tcl +148 -0
  56. siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +1 -1
  57. siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +8 -10
  58. siliconcompiler/tools/openroad/scripts/common/procs.tcl +15 -6
  59. siliconcompiler/tools/openroad/scripts/common/read_liberty.tcl +2 -2
  60. siliconcompiler/tools/openroad/scripts/common/reports.tcl +7 -4
  61. siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +1 -1
  62. siliconcompiler/tools/openroad/scripts/common/write_data_physical.tcl +8 -0
  63. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +16 -12
  64. siliconcompiler/tools/openroad/scripts/rcx/sc_rcx_bench.tcl +2 -4
  65. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +3 -1
  66. siliconcompiler/tools/openroad/write_data.py +2 -2
  67. siliconcompiler/tools/opensta/__init__.py +1 -1
  68. siliconcompiler/tools/opensta/scripts/sc_check_library.tcl +2 -2
  69. siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +2 -2
  70. siliconcompiler/tools/opensta/scripts/sc_timing.tcl +13 -10
  71. siliconcompiler/tools/opensta/timing.py +6 -2
  72. siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +11 -0
  73. siliconcompiler/tools/vivado/scripts/sc_place.tcl +11 -0
  74. siliconcompiler/tools/vivado/scripts/sc_route.tcl +11 -0
  75. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +10 -0
  76. siliconcompiler/tools/vpr/__init__.py +28 -0
  77. siliconcompiler/tools/yosys/scripts/sc_screenshot.tcl +1 -1
  78. siliconcompiler/tools/yosys/scripts/sc_synth_asic.tcl +40 -4
  79. siliconcompiler/tools/yosys/scripts/sc_synth_fpga.tcl +15 -5
  80. siliconcompiler/tools/yosys/syn_asic.py +42 -0
  81. siliconcompiler/tools/yosys/syn_fpga.py +8 -0
  82. siliconcompiler/toolscripts/_tools.json +12 -7
  83. siliconcompiler/toolscripts/ubuntu22/install-keplerformal.sh +72 -0
  84. siliconcompiler/toolscripts/ubuntu24/install-keplerformal.sh +72 -0
  85. siliconcompiler/utils/__init__.py +243 -51
  86. siliconcompiler/utils/curation.py +89 -56
  87. siliconcompiler/utils/issue.py +6 -1
  88. siliconcompiler/utils/multiprocessing.py +46 -2
  89. siliconcompiler/utils/paths.py +21 -0
  90. siliconcompiler/utils/settings.py +162 -0
  91. {siliconcompiler-0.35.3.dist-info → siliconcompiler-0.36.0.dist-info}/METADATA +5 -4
  92. {siliconcompiler-0.35.3.dist-info → siliconcompiler-0.36.0.dist-info}/RECORD +96 -87
  93. {siliconcompiler-0.35.3.dist-info → siliconcompiler-0.36.0.dist-info}/WHEEL +0 -0
  94. {siliconcompiler-0.35.3.dist-info → siliconcompiler-0.36.0.dist-info}/entry_points.txt +0 -0
  95. {siliconcompiler-0.35.3.dist-info → siliconcompiler-0.36.0.dist-info}/licenses/LICENSE +0 -0
  96. {siliconcompiler-0.35.3.dist-info → siliconcompiler-0.36.0.dist-info}/top_level.txt +0 -0
@@ -25,7 +25,7 @@ def show(schema, tech, input_path, output_path, screenshot=False, report=None):
25
25
  layout_options.lefdef_config.produce_obstructions = True
26
26
 
27
27
  # Always use LEF geometry even when LEF file contains FOREIGN statement.
28
- layout_options.lefdef_config.macro_resolution_mode = 1
28
+ layout_options.lefdef_config.macro_resolution_mode = 0
29
29
 
30
30
  tech.load_layout_options = layout_options
31
31
 
@@ -118,9 +118,9 @@ def __screenshot_montage(schema, view, xbins, ybins):
118
118
 
119
119
  app.set_config("background-color", "#000000") # Black
120
120
 
121
- design = schema.get('option', 'entrypoint')
122
- if not design:
123
- design = schema.get('design')
121
+ design_name = schema.get('option', 'design')
122
+ fileset = schema.get("option", "fileset")[0]
123
+ design = schema.get("library", design_name, "fileset", fileset, "topmodule")
124
124
 
125
125
  horizontal_resolution, vertical_resolution = schema.get(
126
126
  'tool', 'klayout', 'task', task, 'var', 'show_resolution', step=step, index=index)
@@ -193,6 +193,7 @@ def main():
193
193
  # SC_ROOT provided by CLI, and is only accessible when this is main module
194
194
  sys.path.append(SC_KLAYOUT_ROOT) # noqa: F821
195
195
  sys.path.append(SC_TOOLS_ROOT) # noqa: F821
196
+ sys.path.append(SC_ROOT) # noqa: F821
196
197
 
197
198
  from klayout_utils import (
198
199
  technology,
@@ -1,7 +1,6 @@
1
1
  import pya
2
2
  import json
3
3
  import shutil
4
- import sys
5
4
  import os.path
6
5
 
7
6
 
@@ -77,7 +76,7 @@ def technology(design, schema):
77
76
 
78
77
  layout_options = tech.load_layout_options
79
78
 
80
- layout_options.lefdef_config.macro_resolution_mode = 1
79
+ layout_options.lefdef_config.macro_resolution_mode = 0
81
80
  layout_options.lefdef_config.via_cellname_prefix = "VIA_"
82
81
  pathed_files = set()
83
82
  for lef_file in layout_options.lefdef_config.lef_files:
@@ -99,6 +98,18 @@ def technology(design, schema):
99
98
  for lef_file in layout_options.lefdef_config.lef_files:
100
99
  print(f"[INFO] LEF file: {lef_file}")
101
100
 
101
+ in_files = layout_options.lefdef_config.macro_layout_files
102
+ for lib in schema.get("asic", "asiclib"):
103
+ libobj = schema.get("library", lib, field="schema")
104
+ for s in get_streams(schema):
105
+ for fileset in libobj.get("asic", "aprfileset"):
106
+ if libobj.valid("fileset", fileset, "file", s):
107
+ in_files.extend(libobj.get("fileset", fileset, "file", s))
108
+ break
109
+ layout_options.lefdef_config.macro_layout_files = in_files
110
+ for lef_file in layout_options.lefdef_config.macro_layout_files:
111
+ print(f"[INFO] Layout file: {lef_file}")
112
+
102
113
  # Set layer properties
103
114
  layer_properties = tech.layer_properties_file
104
115
  if layer_properties:
@@ -129,8 +140,9 @@ def technology(design, schema):
129
140
  map_file = os.path.abspath(os.path.join(os.path.dirname(tech_file),
130
141
  map_file))
131
142
  for s in get_streams(schema):
132
- if schema.valid('library', sc_pdk, 'layermapfileset', 'klayout', 'def', s):
133
- for fileset in schema.get('library', sc_pdk, 'layermapfileset', 'klayout', 'def', s):
143
+ if schema.valid('library', sc_pdk, 'pdk', 'layermapfileset', 'klayout', 'def', s):
144
+ for fileset in schema.get('library', sc_pdk, 'pdk', 'layermapfileset', 'klayout',
145
+ 'def', s):
134
146
  if schema.valid('library', sc_pdk, "fileset", fileset, "file", "layermap"):
135
147
  map_file = schema.get('library', sc_pdk, "fileset", fileset, "file", "layermap")
136
148
  if map_file:
@@ -170,7 +182,6 @@ def get_write_options(filename, timestamps):
170
182
 
171
183
 
172
184
  def get_schema(manifest):
173
- sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
174
185
  from schema.safeschema import SafeSchema
175
186
  return SafeSchema.from_manifest(filepath=manifest)
176
187
 
@@ -1,20 +1,11 @@
1
- from siliconcompiler import Task
1
+ from typing import Optional, Union
2
+
3
+ from siliconcompiler import Task, TaskSkip
2
4
 
3
5
 
4
6
  class TileTask(Task):
5
7
  '''
6
8
  Tiles input images into a single output image.
7
-
8
- Notes:
9
- Need to make ensure that /etc/ImageMagick-6/policy.xml
10
- <policy domain="resource" name="memory" value="8GiB"/>
11
- <policy domain="resource" name="map" value="8GiB"/>
12
- <policy domain="resource" name="width" value="32KP"/>
13
- <policy domain="resource" name="height" value="32KP"/>
14
- <policy domain="resource" name="area" value="1GP"/>
15
- <policy domain="resource" name="disk" value="8GiB"/>
16
- This ensures there are enough resources available to generate
17
- the final image.
18
9
  '''
19
10
 
20
11
  def __init__(self):
@@ -23,6 +14,19 @@ class TileTask(Task):
23
14
  self.add_parameter("bins", "(int,int)", "Number of bins along the (x, y)-axis",
24
15
  defvalue=(2, 2))
25
16
 
17
+ def set_montage_bins(self, xbins: int, ybins: int,
18
+ step: Optional[str] = None, index: Optional[Union[str, int]] = None):
19
+ """
20
+ Set the number of bins for Montage tiling.
21
+
22
+ Args:
23
+ xbins (int): Number of bins along the x-axis.
24
+ ybins (int): Number of bins along the y-axis.
25
+ step (Optional[str]): Flow step to set the parameter for. Defaults to None.
26
+ index (Optional[Union[str, int]]): Index to set the parameter for. Defaults to None.
27
+ """
28
+ self.set("var", "bins", (xbins, ybins), step=step, index=index)
29
+
26
30
  def tool(self):
27
31
  return "montage"
28
32
 
@@ -41,12 +45,22 @@ class TileTask(Task):
41
45
 
42
46
  xbins, ybins = self.get("var", "bins")
43
47
 
48
+ if f"{self.design_topmodule}.png" in self.get_files_from_input_nodes():
49
+ raise TaskSkip("Input provides a single image; skipping tiling.")
50
+
44
51
  for x in range(xbins):
45
52
  for y in range(ybins):
46
53
  self.add_input_file(f'{self.design_topmodule}_X{x}_Y{y}.png')
47
54
 
48
55
  self.add_output_file(ext="png")
49
56
 
57
+ self.add_commandline_option(['-limit', 'memory', '8GiB'])
58
+ self.add_commandline_option(['-limit', 'map', '8GiB'])
59
+ self.add_commandline_option(['-limit', 'disk', '8GiB'])
60
+ self.add_commandline_option(['-limit', 'width', '32KP'])
61
+ self.add_commandline_option(['-limit', 'height', '32KP'])
62
+ self.add_commandline_option(['-limit', 'area', '1GP'])
63
+
50
64
  def runtime_options(self):
51
65
  options = super().runtime_options()
52
66
 
@@ -10,7 +10,7 @@ Sources: https://github.com/The-OpenROAD-Project/OpenROAD
10
10
 
11
11
  Installation: https://github.com/The-OpenROAD-Project/OpenROAD
12
12
  '''
13
- from typing import List, Union
13
+ from typing import List, Union, Optional
14
14
 
15
15
  from siliconcompiler import StdCellLibrary
16
16
  from siliconcompiler import PDK
@@ -346,12 +346,38 @@ class OpenROADStdCellLibrary(StdCellLibrary):
346
346
 
347
347
 
348
348
  class OpenROADTask(ASICTask):
349
+ """
350
+ Base class for tasks involving the OpenROAD EDA tool chain.
351
+
352
+ This class provides common functionality for configuring OpenROAD execution,
353
+ such as setting up debug levels for internal tools.
354
+ """
349
355
  def __init__(self):
350
356
  super().__init__()
351
357
 
352
358
  self.add_parameter("debug_level", "{(str,str,int)}",
353
359
  'list of "tool key level" to enable debugging of OpenROAD')
354
360
 
361
+ def add_openroad_debuglevel(self, tool: str, category: str, level: int,
362
+ step: Optional[str] = None, index: Optional[str] = None,
363
+ clobber: bool = False) -> None:
364
+ """
365
+ Configures the debug logging level for a specific OpenROAD tool and category.
366
+
367
+ Args:
368
+ tool: The name of the OpenROAD tool (e.g., "GRT", "PSM").
369
+ category: The specific debug category or keyword within the tool.
370
+ level: The integer verbosity level for the debug output.
371
+ step: The specific step to apply this configuration to.
372
+ index: The specific index to apply this configuration to.
373
+ clobber: If True, overwrites the existing debug level configuration.
374
+ If False, appends this configuration to the existing list.
375
+ """
376
+ if clobber:
377
+ self.set("var", "debug_level", (tool, category, level), step=step, index=index)
378
+ else:
379
+ self.add("var", "debug_level", (tool, category, level), step=step, index=index)
380
+
355
381
  def tool(self):
356
382
  return "openroad"
357
383
 
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import json
3
3
 
4
- from typing import List
4
+ from typing import List, Union, Optional
5
5
 
6
6
  from siliconcompiler import sc_open
7
7
  from siliconcompiler import utils
@@ -374,9 +374,12 @@ class OpenROADDRTParameter(_OpenROADDRTCommonParameter):
374
374
  self.add_parameter("drt_disable_via_gen", "bool",
375
375
  "true/false, when true turns off via generation in detailed router "
376
376
  "and only uses the specified tech vias", defvalue=False)
377
- self.add_parameter("drt_via_in_pin_bottom_layer", "str", "TODO")
378
- self.add_parameter("drt_via_in_pin_top_layer", "str", "TODO")
379
- self.add_parameter("drt_repair_pdn_vias", "str", "TODO")
377
+ self.add_parameter("drt_via_in_pin_bottom_layer", "str",
378
+ "bottom layer to allow vias inside pins")
379
+ self.add_parameter("drt_via_in_pin_top_layer", "str",
380
+ "top layer to allow vias inside pins")
381
+ self.add_parameter("drt_repair_pdn_vias", "str",
382
+ "layer to repair PDN vias on")
380
383
 
381
384
  self.add_parameter("drt_report_interval", "int",
382
385
  "reporting interval in steps for generating a DRC report.", defvalue=5)
@@ -411,6 +414,14 @@ class OpenROADDRTParameter(_OpenROADDRTCommonParameter):
411
414
 
412
415
 
413
416
  class APRTask(OpenROADTask):
417
+ """
418
+ Base class for OpenROAD-based Automatic Place and Route (APR) tasks.
419
+
420
+ This task initializes specific configurations for OpenROAD, including
421
+ report filtering, image generation settings, heatmap binning, and
422
+ power analysis corners.
423
+ """
424
+
414
425
  def __init__(self):
415
426
  super().__init__()
416
427
 
@@ -423,6 +434,7 @@ class APRTask(OpenROADTask):
423
434
  "fmax",
424
435
  "power",
425
436
  "check_setup",
437
+ "report_buffers",
426
438
  "placement_density",
427
439
  "routing_congestion",
428
440
  "power_density",
@@ -456,11 +468,79 @@ class APRTask(OpenROADTask):
456
468
  self.add_parameter("global_connect_fileset", "[(str,str)]",
457
469
  "list of libraries and filesets to generate connects from")
458
470
 
459
- def add_openroad_globalconnectfileset(self, library, fileset, clobber=False):
471
+ def add_openroad_skipreport(self, report_type: Union[List[str], str],
472
+ step: Optional[str] = None, index: Optional[str] = None,
473
+ clobber: bool = False) -> None:
474
+ """
475
+ Adds or sets report types to be skipped during OpenROAD execution.
476
+
477
+ Args:
478
+ report_type: The name of the report(s) to skip (e.g., 'routing_congestion').
479
+ step: The specific step to apply this configuration to.
480
+ index: The specific index to apply this configuration to.
481
+ clobber: If True, overwrites the existing list of skipped reports.
482
+ If False, appends to the existing list.
483
+ """
484
+ if clobber:
485
+ self.set("var", "skip_reports", report_type, step=step, index=index)
486
+ else:
487
+ self.add("var", "skip_reports", report_type, step=step, index=index)
488
+
489
+ def set_openroad_enableimages(self, enable: bool,
490
+ step: Optional[str] = None, index: Optional[str] = None) -> None:
491
+ """
492
+ Enables or disables the generation of design images at the end of the task.
493
+
494
+ Args:
495
+ enable: True to generate images, False to disable.
496
+ step: The specific step to apply this configuration to.
497
+ index: The specific index to apply this configuration to.
498
+ """
499
+ self.set("var", "ord_enable_images", enable, step=step, index=index)
500
+
501
+ def set_openroad_heatmapbins(self, x: int, y: int,
502
+ step: Optional[str] = None, index: Optional[str] = None) -> None:
503
+ """
504
+ Configures the resolution of the heatmap images.
505
+
506
+ Args:
507
+ x: The number of bins in the X direction.
508
+ y: The number of bins in the Y direction.
509
+ step: The specific step to apply this configuration to.
510
+ index: The specific index to apply this configuration to.
511
+ """
512
+ self.set("var", "ord_heatmap_bins", (x, y), step=step, index=index)
513
+
514
+ def set_openroad_powercorner(self, corner: str,
515
+ step: Optional[str] = None, index: Optional[str] = None) -> None:
516
+ """
517
+ Sets the specific process corner used for power analysis.
518
+
519
+ Args:
520
+ corner: The name of the timing/power corner.
521
+ step: The specific step to apply this configuration to.
522
+ index: The specific index to apply this configuration to.
523
+ """
524
+ self.set("var", "power_corner", corner, step=step, index=index)
525
+
526
+ def add_openroad_globalconnectfileset(self, library: str, fileset: str,
527
+ step: Optional[str] = None, index: Optional[str] = None,
528
+ clobber: bool = False):
529
+ """
530
+ Adds a library and fileset pair to the global connect configuration.
531
+
532
+ Args:
533
+ library: The name of the library.
534
+ fileset: The name of the fileset.
535
+ step: The specific step to apply this configuration to.
536
+ index: The specific index to apply this configuration to.
537
+ clobber: If True, overwrites the existing global connect settings.
538
+ If False, appends to the existing settings.
539
+ """
460
540
  if clobber:
461
- self.set("var", "global_connect_fileset", (library, fileset))
541
+ self.set("var", "global_connect_fileset", (library, fileset), step=step, index=index)
462
542
  else:
463
- self.add("var", "global_connect_fileset", (library, fileset))
543
+ self.add("var", "global_connect_fileset", (library, fileset), step=step, index=index)
464
544
 
465
545
  def setup(self):
466
546
  """
@@ -558,13 +638,22 @@ class APRTask(OpenROADTask):
558
638
  def _add_pnr_outputs(self):
559
639
  self.add_output_file(ext="sdc")
560
640
  self.add_output_file(ext="vg")
641
+ self.add_output_file(ext="lec.vg")
561
642
  self.add_output_file(ext="def")
562
643
  self.add_output_file(ext="odb")
563
644
 
645
+ for lib in self.project.get("asic", "asiclib"):
646
+ libobj = self.project.get("library", lib, field="schema")
647
+ for celltype in ["decap", "tie", "filler", "tap", "endcap", "antenna", "physicalonly"]:
648
+ if libobj.valid("asic", "cells", celltype) and \
649
+ libobj.get("asic", "cells", celltype):
650
+ self.add_required_key(libobj, "asic", "cells", celltype)
651
+
564
652
  def _get_pex_mapping(self):
565
653
  corners = {}
566
- for constraint in self.project.getkeys('constraint', 'timing'):
567
- pexcorner = self.project.get('constraint', 'timing', constraint, 'pexcorner',
654
+ for constraint in self.project.getkeys('constraint', 'timing', 'scenario'):
655
+ pexcorner = self.project.get('constraint', 'timing', 'scenario',
656
+ constraint, 'pexcorner',
568
657
  step=self.step, index=self.index)
569
658
  if pexcorner:
570
659
  corners[constraint] = pexcorner
@@ -572,13 +661,17 @@ class APRTask(OpenROADTask):
572
661
  return corners
573
662
 
574
663
  def _get_constraint_by_check(self, check: str) -> str:
575
- for constraint in self.project.getkeys('constraint', 'timing'):
576
- if check in self.project.get('constraint', 'timing', constraint, 'check',
664
+ for constraint in self.project.getkeys('constraint', 'timing', 'scenario'):
665
+ if check in self.project.get('constraint', 'timing', 'scenario',
666
+ constraint, 'check',
577
667
  step=self.step, index=self.index):
578
668
  return constraint
579
669
 
580
670
  # if not specified, just pick the first constraint available
581
- return self.project.getkeys('constraint', 'timing')[0]
671
+ scenarios = self.project.getkeys('constraint', 'timing', 'scenario')
672
+ if not scenarios:
673
+ raise ValueError("No timing scenarios defined in project constraints.")
674
+ return scenarios[0]
582
675
 
583
676
  def _build_pex_estimation_file(self):
584
677
  corners = self._get_pex_mapping()
@@ -684,9 +777,9 @@ class APRTask(OpenROADTask):
684
777
  ],
685
778
  "peakpower": [
686
779
  *[f"power/{corner}.rpt"
687
- for corner in self.project.getkeys('constraint', 'timing')],
780
+ for corner in self.project.getkeys('constraint', 'timing', 'scenario')],
688
781
  *[f"images/heatmap/power_density/{corner}.png"
689
- for corner in self.project.getkeys('constraint', 'timing')]
782
+ for corner in self.project.getkeys('constraint', 'timing', 'scenario')]
690
783
  ],
691
784
  "drvs": [
692
785
  "timing/drv_violators.rpt",
@@ -26,6 +26,7 @@ class CTSTask(APRTask, OpenROADSTAParameter, OpenROADDPLParameter, OpenROADCTSPa
26
26
  'power',
27
27
  'drv_violations',
28
28
  'fmax',
29
+ 'report_buffers',
29
30
 
30
31
  # Images
31
32
  'placement_density',
@@ -37,6 +37,7 @@ class GlobalPlacementTask(APRTask, OpenROADSTAParameter, OpenROADGPLParameter,
37
37
  'unconstrained',
38
38
  'power',
39
39
  'fmax',
40
+ 'report_buffers',
40
41
 
41
42
  # Images
42
43
  'placement_density',
@@ -1,3 +1,5 @@
1
+ from typing import Union, List, Optional
2
+
1
3
  from siliconcompiler.tools.openroad._apr import APRTask
2
4
  from siliconcompiler.tools.openroad._apr import OpenROADSTAParameter, OpenROADPPLParameter
3
5
 
@@ -5,9 +7,13 @@ from siliconcompiler.tools.openroad._apr import OpenROADSTAParameter, OpenROADPP
5
7
  class InitFloorplanTask(APRTask,
6
8
  OpenROADSTAParameter,
7
9
  OpenROADPPLParameter):
8
- '''
9
- Perform floorplanning and initial pin placements
10
- '''
10
+ """
11
+ Perform floorplanning and initial pin placements.
12
+
13
+ This task handles the initialization of the floorplan, including macro placement
14
+ snapping strategies, cleaning up synthesis artifacts (buffers/dead logic),
15
+ and defining padring or bumpmap configurations.
16
+ """
11
17
  def __init__(self):
12
18
  super().__init__()
13
19
 
@@ -19,6 +25,79 @@ class InitFloorplanTask(APRTask,
19
25
  "remove logic which does not drive a primary output", defvalue=True)
20
26
 
21
27
  self.add_parameter("padringfileset", "[str]", "filesets to generate a padring")
28
+ self.add_parameter("bumpmapfileset", "[str]", "filesets to generate a bumpmap")
29
+
30
+ def set_openroad_snapstrategy(self, snap: str,
31
+ step: Optional[str] = None, index: Optional[str] = None):
32
+ """
33
+ Sets the snapping strategy for macro placement.
34
+
35
+ Args:
36
+ snap: The snapping mode. Options are typically 'none', 'site', or 'grid'.
37
+ step: The specific step to apply this configuration to.
38
+ index: The specific index to apply this configuration to.
39
+ """
40
+ self.set("var", "ifp_snap_strategy", snap, step=step, index=index)
41
+
42
+ def set_openroad_removebuffers(self, enable: bool,
43
+ step: Optional[str] = None, index: Optional[str] = None):
44
+ """
45
+ Enables or disables the removal of buffers inserted during synthesis.
46
+
47
+ Args:
48
+ enable: True to remove synthesis buffers, False to keep them.
49
+ step: The specific step to apply this configuration to.
50
+ index: The specific index to apply this configuration to.
51
+ """
52
+ self.set("var", "remove_synth_buffers", enable, step=step, index=index)
53
+
54
+ def set_openroad_removedeadlogic(self, enable: bool,
55
+ step: Optional[str] = None, index: Optional[str] = None):
56
+ """
57
+ Enables or disables the removal of logic that does not drive a primary output.
58
+
59
+ Args:
60
+ enable: True to remove dead logic, False to keep it.
61
+ step: The specific step to apply this configuration to.
62
+ index: The specific index to apply this configuration to.
63
+ """
64
+ self.set("var", "remove_dead_logic", enable, step=step, index=index)
65
+
66
+ def add_openroad_padringfileset(self, fileset: Union[str, List[str]],
67
+ step: Optional[str] = None, index: Optional[str] = None,
68
+ clobber: bool = False):
69
+ """
70
+ Adds fileset(s) used to generate the I/O pad ring.
71
+
72
+ Args:
73
+ fileset: A string name or list of names representing the padring filesets.
74
+ step: The specific step to apply this configuration to.
75
+ index: The specific index to apply this configuration to.
76
+ clobber: If True, overwrites the existing padring fileset list.
77
+ If False, appends to the existing list.
78
+ """
79
+ if clobber:
80
+ self.set("var", "padringfileset", fileset, step=step, index=index)
81
+ else:
82
+ self.add("var", "padringfileset", fileset, step=step, index=index)
83
+
84
+ def add_openroad_bumpmapfileset(self, fileset: Union[str, List[str]],
85
+ step: Optional[str] = None, index: Optional[str] = None,
86
+ clobber: bool = False):
87
+ """
88
+ Adds fileset(s) used to generate the bump map for flip-chip or 3D designs.
89
+
90
+ Args:
91
+ fileset: A string name or list of names representing the bumpmap filesets.
92
+ step: The specific step to apply this configuration to.
93
+ index: The specific index to apply this configuration to.
94
+ clobber: If True, overwrites the existing bumpmap fileset list.
95
+ If False, appends to the existing list.
96
+ """
97
+ if clobber:
98
+ self.set("var", "bumpmapfileset", fileset, step=step, index=index)
99
+ else:
100
+ self.add("var", "bumpmapfileset", fileset, step=step, index=index)
22
101
 
23
102
  def task(self):
24
103
  return "init_floorplan"
@@ -62,8 +141,41 @@ class InitFloorplanTask(APRTask,
62
141
  for fileset in self.get("var", "padringfileset"):
63
142
  self.add_required_key(self.project.design, "fileset", fileset, "file", "tcl")
64
143
 
65
- def add_openroad_padringfileset(self, fileset: str, clobber=False):
66
- if clobber:
67
- self.set("var", "padringfileset", fileset)
144
+ if self.get("var", "bumpmapfileset"):
145
+ self.add_required_key("var", "bumpmapfileset")
146
+
147
+ for fileset in self.get("var", "bumpmapfileset"):
148
+ self.add_required_key(self.project.design, "fileset", fileset, "file", "bmap")
149
+
150
+ # Mark requires for components, pin, and floorplan placements
151
+ for component in self.project.constraint.component.get_component().values():
152
+ if component.get_placement(step=self.step, index=self.index) is not None:
153
+ self.add_required_key(component, "placement")
154
+ self.add_required_key(component, "rotation")
155
+ if component.get_halo(step=self.step, index=self.index) is not None:
156
+ self.add_required_key(component, "halo")
157
+ if component.get_partname(step=self.step, index=self.index):
158
+ self.add_required_key(component, "partname")
159
+
160
+ for pin in self.project.constraint.pin.get_pinconstraint().values():
161
+ if pin.get_placement(step=self.step, index=self.index) is not None:
162
+ self.add_required_key(pin, "placement")
163
+ if pin.get_layer(step=self.step, index=self.index) is not None:
164
+ self.add_required_key(pin, "layer")
165
+ if pin.get_side(step=self.step, index=self.index) is not None:
166
+ self.add_required_key(pin, "side")
167
+ if pin.get_order(step=self.step, index=self.index) is not None:
168
+ self.add_required_key(pin, "order")
169
+
170
+ self.add_required_key(self.mainlib, "asic", "site")
171
+ if self.project.constraint.area.get_diearea(step=self.step, index=self.index) and \
172
+ self.project.constraint.area.get_corearea(step=self.step, index=self.index):
173
+ self.add_required_key(self.project.constraint.area, "diearea")
174
+ self.add_required_key(self.project.constraint.area, "corearea")
68
175
  else:
69
- self.add("var", "padringfileset", fileset)
176
+ self.add_required_key(self.project.constraint.area, "aspectratio")
177
+ self.add_required_key(self.project.constraint.area, "density")
178
+ self.add_required_key(self.project.constraint.area, "coremargin")
179
+
180
+ if self.mainlib.get("tool", "openroad", "tracks"):
181
+ self.add_required_key(self.mainlib, "tool", "openroad", "tracks")